noip模拟赛 集合
分析:感觉像是贪心,再看数据范围这么大,肯定是贪心没错.但是要怎么贪呢?主要的思想是让每次往上加的数尽量多,肯定要先把0分裂,如果能正好一起跳到最终状态就好.举个例子:5,3,2,1,最大值比次大值大2,所以肯定有一个0先跳两下,另外一个0分裂,等到第一个0跳了两下后再接着跳,这样手推感觉有点复杂,于是就想,5,3,2,1这个状态从哪个状态转移过来呢?4,2,1,0,再往回转移3,1,0,0,两个0肯定是由一个0分裂而来的,再上一个状态是2,0,0,不断的合并,直到只剩下一个0.那么贪心的方法就出来了:倒着贪心.
正着想构造不出来方法,可以倒着从已知状态来得到.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, a[1000010], cnt[1000010], tot, ans, maxx; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); cnt[a[i]]++; maxx = max(maxx, a[i]); } tot = cnt[0]; for (int i = 1; i <= maxx; i++) { ans++; tot = (tot + 1) / 2; tot += cnt[i]; } while (tot > 1) { tot = (tot + 1) / 2; ans++; } printf("%d\n", ans); return 0; }