bnuoj24252 Divide
Alice and Bob has found a island of treasure in byteland! They find N kinds of treasures on the island, and each kind of treasure has a certain number, and as in byteland, the value of each treasure will be a power
of 2, such as 1,2,4,8 ...
Now the only problem is how to divide treasures fairly, they need to divide the treasures into two parts, and the value of each part is the sum of all treasures' in this part, they want to make the difference between the value of two parts as small as possible,
can you help them?
Input
First line of the input is a single integer T(1 <= T <= 20), indicating there are T test cases.
For each test case, the first line contain one integer N(2 <= N <= 10^5), indicate the different kinds of treasures.
Then N line followed, each line will have follow two integer ai(0 <= ai <= 10^5) and xi(0 <= xi <= 10^9), indicate there are xi i-th treasures, and the value of each one is 2^ai.
Output
For each case, you should output a single line, first output "Case #t: ", where t indicating the case number between 1 and T, then a string with only '0' and '1' followed, indicate the minimum difference in binary
representation, find more details in samples.
Sample Input
3
2
0 2
2 1
4
0 1
1 1
2 1
3 1
4
0 2
1 1
2 1
3 1
Sample Output
Case #1: 10
Case #2: 1
Case #3: 0
这题是道二进制想法题,给你n种2^a[i]次,num[i]件的物品,问你怎样分配为两堆物品能使两堆的差值最小。这里我们可以把读入的每件物品都用二进制储存起来,用num[i]表示二进制第i位上的数,用jinwei[i]表示这一位是否由前一位进位得到。
然后从高位到低位循环,直到没有进位的且为1的那位退出,那么最小的差值即为当前的位数所表示的数减去其低位加起来的总数。为什么这样是对的呢,因为如果是0或者2,那么一定可以平分,如果是1,且是由进位得到的,那么这个进位可以表示为2个较低位的数。而且2^i>2^(i-1)+2^(i-2)+2^(i-3)+...+2^0,所以这样差值一定是最小的。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x7fffffff
#define maxn 106000
struct node{
ll num,v;
}a[maxn],b[maxn];
ll jinwei[maxn],num[maxn],ans[maxn];
int main()
{
ll n,m,i,j,T,tot,cnt,cas=0;
scanf("%lld",&T);
while(T--)
{
memset(num,0,sizeof(num));
memset(jinwei,0,sizeof(jinwei));
memset(ans,0,sizeof(ans));
scanf("%lld",&n);
for(i=1;i<=n;i++){
scanf("%lld%lld",&a[i].v,&a[i].num);
num[a[i].v+1]+=a[i].num;
}
tot=0;
for(i=1;i<=105000;i++){
if(num[i]==0)continue;
if(num[i]==1){
tot=i;continue;
}
tot=i;
if(num[i]%2==0){
num[i+1]+=num[i]/2;jinwei[i+1]=1;
num[i]=0;
}
else{
num[i+1]+=num[i]/2;jinwei[i+1]=1;
num[i]=1;
}
}
j=10000000000;
for(i=tot;i>=1;i--){
if(num[i]==0)continue;
if(num[i]==1){
if(jinwei[i]==1)continue;
else{
j=i;break;
}
}
}
if(j==10000000000){
cas++;
printf("Case #%lld: 0\n",cas);continue;
}
if(j==1){
cas++;
printf("Case #%lld: 1\n",cas);continue;
}
for(i=j-1;i>=1;i--){
ans[i]=1-num[i];
}
ans[1]++;
tot=0;
for(i=1;i<=105000;i++){
if(ans[i]==0)continue;
if(ans[i]==1){
tot=i;continue;
}
tot=i;
if(ans[i]%2==0){
ans[i+1]+=ans[i]/2;
ans[i]=0;
}
else{
ans[i+1]+=ans[i]/2;
ans[i]=1;
}
}
cas++;
printf("Case #%lld: ",cas);
for(i=tot;i>=1;i--){
printf("%lld",ans[i]);
}
printf("\n");
}
return 0;
}