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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章