jzoj3781 multiset

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);

}
發佈了58 篇原創文章 · 獲贊 1 · 訪問量 6146
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章