http://acm.hdu.edu.cn/showproblem.php?pid=5573
题意:
给出一个满二叉树,根节点权值为1,左儿子为2*val,右儿子为2*val+1。现在有只青蛙从根节点出发,一步步往下走,在每个节点它都要选择加上该点的权值还是减去该点的权值,如果正好经过k个节点时总的权值和为n,那么这只青蛙就成功了,需要输出方案。
思路:
这道题目要注意到n<=(1<<k)。
所以如果每次都走这棵二叉树的左节点的话,权值就是1,2,4,8,10,那么它就可以组成小于(1<<k)的所有偶数,如果组成所有奇数的话,只要最后一步走右节点即可。
现在设走左节点的权值和是sum,那么多余的部分就是sum-n,那么我们只需要把(sum-n)/2这部分变成负数就可以,那么这里就又存在一个问题了,就是sum-n有可能是奇数,如果是这种情况的话就让最后一步走右节点,这样的话sum-n就又变成偶数了。
那么怎么去凑(sum-n)/2呢,很简单,还是根据二进制,相应位的节点改为负即可。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn = 100+5; 5 typedef long long ll; 6 7 int n, k; 8 int a[maxn]; 9 10 int main() 11 { 12 //freopen("in.txt","r",stdin); 13 int T; 14 int kase = 0; 15 scanf("%d",&T); 16 while(T--) 17 { 18 bool flag = false; 19 scanf("%d%d",&n,&k); 20 ll sum = (1<<k)-1; 21 ll rest = sum - n; 22 if(rest&1) {flag = true; rest++;} 23 rest/=2; 24 for(int i=0;i<k;i++) 25 { 26 if(rest&((ll)1<<i)) a[i]=0; 27 else a[i]=1; 28 } 29 printf("Case #%d: ",++kase); 30 for(int i=0;i<k;i++) 31 { 32 if(i!=k-1) printf("%lld ",(ll)1<<i); 33 else if(flag) printf("%lld ",(ll)(1<<i)+1); 34 else printf("%lld ",(ll)1<<i); 35 if(a[i]) puts("+"); 36 else puts("-"); 37 } 38 } 39 return 0; 40 }