题意:
给你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;
}