第一题是一个很水的题目,其实就是让你求有多少个J右边的O的数量乘下面的I的数量之和。
最开始的想法,显然是写一个暴力,外面两层枚举J,中间两层枚举O,后面两层枚举I,这样复杂度显然是O(N^6)次方级别的,你就获得了15.36分左右的好成绩。
有没有O(1)查询每一个J的方法吗?很简单我们只需要维护一个二位前缀和即可,这样复杂度可以降到O(N^2),可以通过N<=3000的数据。
顺便吐槽一下,这题为什么要卡常啊,我谔谔。。。
所以这题需要IO优化,否则你只能获得,71.79~84.69得分
MY CODE
#include<bits/stdc++.h> using namespace std; long long ans=0; long long s[3005][3005];//分别记录O和I long long t[3005][3005]; char c[3005][3005]; int main() { ios::sync_with_stdio(false);//IO优化 int n; int m; cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>c[i][j]; } } for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { s[i][j]=s[i][j+1]+(c[i][j]=='O');//算每一个O } } for(int j=1;j<=m;j++) { for(int i=n;i>=1;i--) { t[i][j]=t[i+1][j]+(c[i][j]=='I');//算每一个I } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(c[i][j]=='J') ans+=s[i][j]*t[i][j];//统计答案就可以了了 } } cout<<ans; return 0; //完美的结束 }
很多同学看到这,可能会觉得可以用树状数组来维护,但是这样复杂度是O(NlogN)的,所以可能会被卡掉。
第二题是一个贪心,
先考虑暴力,我们可以外层枚举画,里层枚举画框,之后挨个试,这样复杂度显然是O(NM)的可以获得53.25左右的高分。
我们可以看正解:我们可以先将画排一下序,使用一个结构体(这样数据不会乱),之后再将画框排一下序,之后挨个扫描,如果可以装进当前画框,那么答案就加,否则将画框的编号加一下,知道能放下,如果画框编号已经到N个说明后面的画一定都装不下,所以只要输出i-1就行了,如果最后编号还是没到N,就说明所有画都可以装进去只要输出M就可以啦!
由于我们已经将画(按美观程度排序),画框也都排序了,所以不需要考虑,题面中说的那两个条件。这样复杂度显然是排序的复杂度即O(NlogN+MlogM),可以通过本题。
MY CODE
#include <bits/stdc++.h> using namespace std; struct h{ int x; int y; }a[100005]; bool cmp(h p,h q) { if(p.y==q.y) return p.x>q.x; return p.y>q.y; } bool compare(int p,int q) { return p>q; } int main() { int n; int m; cin>>n>>m; int c[100005]; for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y; sort(a+1,a+n+1,cmp);//将画排序 for(int i=1;i<=m;i++) cin>>c[i]; sort(c+1,c+m+1,compare);//将画框排序 int o=1; for(int i=1;i<=m;i++) { while(o<=n&&a[o].x>c[i]) //看能否装得下 o++; if(o>n)//看是否编号已到N { cout<<i-1<<endl;//输出当前编号-1 return 0; } o++; } cout<<m<<endl; return 0; }
第三道题是一个垃圾DP,我不会(哭
第四题相对比较简单,是一个纯模拟
对于前36个点,我们可以纯爆搜去做,复杂度较玄学,可以拿到34.92的高分。
而对于满分,我们可以将硬币先移动到离他最近的格子,这是会有一些地方有很多,而一些地方却没有,我们可以扫描一下每一列,可以类似的理解为一个贪心,如果有空的地方,就移过来一些,否则将这列多余的硬币全部拿走。复杂度也比较玄学差不多O(N)的,可以通过此题。
MY CODE
#include <bits/stdc++.h> using namespace std; int b[1000005][3]; int main() { int n; cin>>n; long long ans=0; for(int x,y,i=1;i<=2*n;i++) { cin>>x>>y; if(x<1) { ans+=1-x; x=1; } if(x>n) { ans+=x-n; x=n; } if(y<1) { ans+=1-y; y=1; } if(y>2) { ans+=y-2; y=2; } //往近的地方放 b[x][y]++;//将有硬币的地方加一下(类似于一个桶) } for(int i=1,x=0,y=0;i<=n;i++) { x+=b[i][1]-1; y+=b[i][2]-1; while(x<0&&y>0) { x++; y--; ans++; } while(x>0&&y<0) { x--; y++; ans++; } //按照上过程模拟即可 if(i<n) ans+=abs(x)+abs(y);//计算答案 } cout<<ans; return 0; }
第五题是一道长链剖分的模板题,可是我不会这种高级的玩意,其实思路并不是很难,大家可以自己去思考思考。
希望大家,理解了再抄。
谢谢观看,再见啦!