Codeforces725E Too Much Money【枚举】
分析:容易注意到答案只可能是加一个金币。因为加两个可以规约为加一个。
所以可以枚举加的金币为i,然后依照题意模拟扣金币的过程。每次找到一个当前能扣的最大的金币,一次性把这种金币扣完。这样每种金币只被找到一次,由$1+2+...+n=n(n+1)/2$可以推得最多找到$\sqrt n$种金币。预处理当前最大能找的金币为$x$时找到的金币,可以做到$O(c\sqrt c)$
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 202000; 5 6 int c,n; 7 int a[maxn]; 8 int cnt[maxn]; 9 int pre[maxn]; 10 11 int check(int coin,int now){ 12 int lastget = coin; 13 while(coin){ 14 int dt = 0; 15 if(lastget >= now) dt = max(now,pre[lastget]); 16 else dt = pre[lastget]; 17 if(dt == 0) break; 18 if(coin - 1ll*cnt[dt]*dt <= 0){ 19 coin %= dt; 20 }else{ 21 coin -= cnt[dt]*dt; 22 } 23 lastget = min(coin,dt-1); 24 } 25 if(coin == 0) return 0; 26 else return 1; 27 } 28 29 int main(){ 30 scanf("%d%d",&c,&n); 31 for(int i=1;i<=n;i++){ 32 scanf("%d",&a[i]); 33 cnt[a[i]]++; 34 pre[a[i]] = a[i]; 35 } 36 for(int i=1;i<=c;i++){ 37 if(!pre[i]) pre[i] = pre[i-1]; 38 } 39 for(int i=1;i<=c;i++){ 40 cnt[i]++; 41 if(check(c,i)){ 42 printf("%d\n",i); 43 return 0; 44 } 45 cnt[i]--; 46 } 47 puts("Greed is good"); 48 return 0; 49 }