题目链接:http://codeforces.com/problemset/problem/1183/D
思路:
这个题真是折磨死我了,我一开始用的方法是先用a数组存储数值出现的次数,然后再用b数组记录出现该次数的次数,下表即次数,值即次数的次数,然后从后往前遍历,如果次数的次数大于1,就加到前面,最后超时。后来我还想了很多办法,都超时,最后我直接舍弃b数值,用排序这个方法。后来我想的方法是先用a数组存储数值出现的次数,然后从大到小排序,然后用flag记录目前要加的次数,然后遍历a数组,如果数值大于flag,就加flag,如果小于flag,就加该数值,其实这个方法是正确的,但还是超时,我就开始怀疑人生了,终于,我发现自己哪里错了,我用的memset这个函数导致的超时,这个函数写起来方便,但不如for循环快,for循环可以局部赋值。
AC代码
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAX=2e5+20; int a[MAX]; bool cmp(int x,int y){return x>y;} int main() { int n; cin>>n; while(n--) { int num; cin>>num; // memset(a,0,sizeof(a)); 不能乱用了,时间超限就是因为它 for(int i=0;i<=num;i++)a[i]=0; int t; int ans=0; int maxNum=0; for(int i=1;i<=num;i++) { cin>>t; a[t]++; if(t>maxNum)maxNum=t; } sort(a,a+maxNum+1,cmp); int flag=a[0]; for(int i=0;i<=maxNum;i++) { if(a[i]<=0||flag<=0)break; if(flag>a[i])flag=a[i]; ans+=flag; flag--; } cout<<ans<<endl; } return 0; }