分析:
显而易见的是 ,如果依照题意进行模拟操作,会发现,很难确定终点。
此时可以应用逆向思维,对每个数进行反向运算。
即,操作变为对集合中的每个数x:
1. x=x-1 2. 合并两个数 a,b x=a+b 3. 不对x进行操作
复杂度:
时间复杂度:O(n log n)
空间复杂度:O(n)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=1e7+7; int N,Ans,T[maxn],X[maxn]; inline int Read(void) { int x=0,w=0; char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=x*10+(ch^48),ch=getchar(); return w?-x:x; } bool CMP(const int A,const int B) { return A>B; } int main(void) { N=Read(); for(int i=1; i<=N; ++i) { T[i]=Read(); ++X[T[i]];//统计每个数字出现次数 } sort(T+1,T+1+N,CMP);//PS:逆向操作 int Z=X[0]; for(int i=1; i<=T[1]; ++i)//把每个数清零 { ++Ans;//累计轮数 Z=(Z+1)/2;///合并数字 Z+=X[i];//增加新数字 } for(Z; Z>1; Z=(Z+1)/2) ++Ans;//记录合并剩余数字次数 printf("%d",Ans); return 0; }