UESTC 1711 Divide
/* http://acm.uestc.edu.cn/problem.php?pid=1711&cid=169 题意:岛上有n种宝藏,每一种宝藏有x个,它的价值为2^a。(x<10^9,a<10^5) 现在给出n种宝藏的个数x和价值a,要你将它分成两份是它们差值最小并输出差值。 思路:开始以为是背包问题,但是做不出来,正确的做法是:跟它的价值是2的次方有关系。 假如宝藏有x个,而x是个奇数,那么没办法我们只能把一边多分一个2^a(先保存好,等下再讨论分给谁)。 剩余的我们不分把她它弄成是(x/2)个价值为2^(a+1)的宝藏。(这里我们需要从a最小的开始)这样一直往上推,把宝藏弄成全部是bc[i][0]*2^i的形式, 而bc[i][1]记录是否由下面2^(i-1)生成的(其中bc[i][0]=1(或0),表示有(没有)2^i的这种宝藏,bc[i][1]=1(或0),表示由(不由)2^(i-1)构成)。 我现在又从高位往低位判断, 1、如果2^j不存在,继续往下分配。 2、如果存在则分两种情况讨论 (1)、这个宝藏是由2^(j-1)构成的,那么我们把这种宝藏分成2^(j-1),平均分配给两边。继续往下分配。 (2)、如果不是,我们把这个宝藏分配给一边,把比这个宝藏阶层小的分配给另一边。分配结束。 差值为2^(j)-bc[j-1][0]*2^(j-1)-bc[j-2][0]*2^(j-2)-……-bc[0][0]*2^0; 输出其对应的2进制即可。 */ #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct node{ long long a,x; }ac[1100000]; long long bc[1100000][2]; bool cmp(node aa,node bb) { return aa.a<bb.a;} int main() { long long t,n,c,cnt=1; long long i,j; scanf("%lld",&t); while(t--) { scanf("%lld",&n); for(i=0;i<n;i++) scanf("%lld %lld",&ac[i].a,&ac[i].x); sort(ac,ac+n,cmp); memset(bc,0,sizeof(bc)); int len=0; for(i=1;i<n;i++) if(ac[len].a==ac[i].a) ac[len].x+=ac[i].x; else { len++; ac[len].a=ac[i].a; ac[len].x=ac[i].x; } c=0;j=0; for(i=0;i<=ac[len].a;i++) { if(j<n&&i==ac[j].a){ if(c>0) bc[i][1]=1; c+=ac[j].x; j++; bc[i][0]=c%2; c/=2; } else { bc[i][0]=c%2; bc[i][1]=1; c/=2; } } for(i=ac[len].a;i>0;i--) if(bc[i][0]==0||(bc[i][0]==1&&bc[i][1]==1)) bc[i][0]=0; else break; printf("Case #%lld: ",cnt++); if(i==0) printf("%lld\n",bc[0][0]); else { c=0; for(j=0;j<=i;j++) { if(c==0) { bc[j][0]^=c; c=bc[j][0]; } else bc[j][0]^=c; } while(bc[i][0]==0) i--; for(j=i;j>=0;j--) printf("%lld",bc[j][0]); printf("\n"); } } return 0; }