D. Candy Box (easy version)
http://codeforces.com/contest/1183/problem/D
这题本来是一个简单题,但是不可以开数组来解决,开数组需要把数组的大小开到2*10^5,当很q大并且n很大时,使用sort排序时会TLE。所以这里我们使用C++中的vector容器构建一个长度为n+1的向量列解决这个问题,这就避免了每次在读取数据时需要对20000个数据进行排序,而只需对我们读取的数据进行排序,因此不会超时。
具体做法:维护一个长度为n+1的向量,长度为n+1是因为数据ai范围为1≤ai≤n,然后对该向量进行模拟,定义中间变量ans和总和sum,设置ans=cnt[0]的原因是至少可以在礼物中准备cnt[0]个糖果,所以sum的初始值也设置为cnt[0],在模拟的过程中,当cnt[i]>=ans时,第一次模拟的时候cnt[i]只可能等于ans,因为对cnt进行了从大到小的排序,cnt[i+1]<=cnt[i],但随着模拟的进行,ans的减小,cnt[i]会大于ans的值,这就相当于我有四种种类的糖果,每种糖果的都有4个,在第一次取4个后,为满足题目要求,后面几种只能取3,2,1种了,而当cnt[i]小于ans时,我们直接可以加上cnt[i],这时候我们需要对ans进行更新,使得ans=cnt[i]。
对应代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <set> 4 #include <vector> 5 #include <algorithm> 6 const int maxn=200010; 7 using namespace std; 8 int main() 9 { 10 //set<int> s; 11 int q,n; 12 scanf("%d",&q); 13 while(q--) 14 { 15 //s.clear(); 16 //int cnt[maxn]={0}; 17 scanf("%d",&n); 18 vector<int> cnt(n+1); 19 for(int i=0;i<n;i++) 20 { 21 int x; 22 scanf("%d",&x); 23 cnt[x]++; 24 } 25 sort(cnt.rbegin(),cnt.rend()); //C++vector逆序迭代器 26 int ans=cnt[0]; 27 int sum=cnt[0]; 28 for(int i=1;i<n;i++) 29 { 30 if(ans==0) 31 break; 32 if(cnt[i]>=ans) 33 { 34 sum+=(ans-1); 35 ans--; 36 } 37 else 38 { 39 sum+=cnt[i]; 40 ans=cnt[i]; 41 } 42 } 43 printf("%d\n",sum); 44 } 45 return 0; 46 }