題意:
給你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;
}