cdoj 86 Divide

題意:

    給你n種物品,每種物品的價值是2^a(0<=a<=1e5),每種物品有b(0<=b<=1e9)個,讓你把這些物品分成兩堆,讓兩堆之間的差值最小。

做法:

    首先我們從高位向低位看
    1.如果這位上的個數恰好是偶數,那麼是不是就可以平均分?
    2.然後如果是奇數的話,是不是就要看看它後面的數能不能補足這個差值?
    那麼這樣的話。我們先預處理一下,把所有的位都進位化成2進制。
    這樣的話,如果這一位是進位來的,即便他是1個,那麼也無妨啊,因爲進位來的這個1個可以分開啊。。
    然後就好辦啦。我們只需要找到最大的那個不是進位來的且值是1的位置在哪裏就好了。 然後就是減法了。減法這裏有個技巧。 100000可以化成11111 + 1;然後就簡單了。

code

#include <bits/stdc++.h>
using namespace std;
int T;
int n;
long long a[100100];
bool is[100100];
int icase = 0;
long long ans[100100];
int main(){
    cin>>T;
    while(T--){
        cin>>n;
        memset(a, 0, sizeof(a));
        memset(is, false, sizeof(is));
        memset(ans, 0, sizeof(ans));
        int x,c;
        for(int i=1; i<=n; i++){
            scanf("%d %d", &x, &c);
            a[x] += c;
        }
        for(int i=0; i<=100000; i++){
            if(a[i] >= 2){
                a[i+1] += a[i]/2;    
                a[i] %= 2;
                is[i+1] = true;
            }
        }
        int id = -1;
        for(int i=100000; i>=0; i--){
            if(a[i] == 1 && is[i] == false)
            {id = i; break;}
        }
        printf("Case #%d: ", ++icase);
        if(id == -1) {
            puts("0"); continue;
        }
        for(int i=id-1; i>=0; i--)
            ans[i] = (1 ^ a[i]);
        ans[0] += 1;
        for(int i=0; i<=id-1; i++)
            ans[i+1] += ans[i]/2,ans[i] %= 2;
        for(int i=100000; i>=0; i--){
            if(ans[i] == 0) continue;
            for(int j=i; j>=0; j--)
                printf("%lld", ans[j]);
            i = 0;
        }
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章