题解:贪心
有一个比较显然的思路就是尽可能快的将数分解,然后同时进行第一种操作。
有一个错误的思路,就是先分解成最终状态的个数,然后直到加到最大的数为止。这样为啥不对?因为你最后在+1的时候很多数都闲着了,那么不如在某些数+1的同时让某些位置分解。
于是我们考虑将操作撤销,每次讲能-1的都-1,然后同时将0两两合并,这样贪心一定是最优的。
所以我根据权值排序然后两个指针扫一遍即可。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 1000003
using namespace std;
int a[N],n;
int cmp(int x,int y)
{
return x>y;
}
int main()
{
freopen("multiset.in","r",stdin);
freopen("multiset.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
// for (int i=1;i<=n;i++) cout<<a[i]<<" ";
// cout<<endl;
int l=n; int r=n; int t=0;
while (!a[l]) l--;
int ans=0;
while (true) {
int size=(r-l)/2;
r-=size;
t++; ans++;
if (r==1) break;
while (a[l]==t&&l) l--;
}
printf("%d\n",ans);
}