Description
Alice 正在玩一個 multiset。最初,集合中只有一個元素 0。每一輪,集合中的每一個元素 x 都有 3 種可能的操作:
1、x 加上 1.即 x = x +1。
2、x 分裂成兩個非負整數 y, z。即 x = y + z, 且 y >=0, z >= 0。
3、什麼都不做。
注意,在一輪中每個元素只能選擇一種操作。
Alice 已經玩了很久了, 但她並不知道自己已經玩了多少輪。 現在給出最終的集合,請你輸出 Alice 最少玩的輪數。
Input
第一行爲一個整數N,描述最終集合的大小。
第二行爲N個非負整數,爲最終集合的每一個元素。
Output
輸出唯一一行,Alice 最少玩的輪數。
Sample Input
Sample Input 1
1
0
Sample Input 2
4
1 1 1 1
Sample Input 3
5
0 3 0 3 0
Sample Output
Sample Output 1
0
Sample Output 2
3
Sample Output 3
5
Data Constraint
對於 10%的數據,N <= 10,A[i] <= 10
對於 30%的數據,N <= 50,A[i] <= 100
對於 50%的數據,N <= 1000,A[i] <= 10,000
對於 100%的數據,N <= 1,000,000,A[i] <= 1,000,000
Solution
覺得這一題非常得巧妙
首先,貪心的思路並不難想到
肯定是先分裂再增加
這樣做的正確性顯然
但是這樣子並不好做
那麼,正難則反
從末狀態也就是題目給定的狀態開始做
把大於0的數全部減到0,爲0的數進行合併,直到只剩下最後一個零即可
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int n,i,ans,a[1000005],t,x;
int read(){
int sum=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9'){
sum=sum*10+c-'0';
c=getchar();}
return sum;
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();
fo(i,1,n) {x=read();a[x]++;t=max(t,x);}
fo(i,1,t){
if (a[0]>1) a[0]=a[0]-a[0]/2;
a[0]+=a[i];}
ans=t;
while (a[0]>1) ans++,a[0]=a[0]-a[0]/2;
printf("%d\n",ans);
}