HDU5573 Binary Tree

来源:互联网 发布:php开源erp系统 编辑:程序博客网 时间:2024/05/18 03:04

Binary Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 37    Accepted Submission(s): 20
Special Judge


Problem Description
The Old Frog King lives on the root of an infinite tree. According to the law, each node should connect to exactly two nodes on the next level, forming a full binary tree.

Since the king is professional in math, he sets a number to each node. Specifically, the root of the tree, where the King lives, is 1. Say froot=1.

And for each node u, labels as fu, the left child is fu×2 and right child is fu×2+1. The king looks at his tree kingdom, and feels satisfied.

Time flies, and the frog king gets sick. According to the old dark magic, there is a way for the king to live for another N years, only if he could collect exactly Nsoul gems.

Initially the king has zero soul gems, and he is now at the root. He will walk down, choosing left or right child to continue. Each time at node x, the number at the node is fx (remember froot=1), he can choose to increase his number of soul gem by fx, or decrease it by fx.

He will walk from the root, visit exactly K nodes (including the root), and do the increasement or decreasement as told. If at last the number is N, then he will succeed.

Noting as the soul gem is some kind of magic, the number of soul gems the king has could be negative.

Given N, K, help the King find a way to collect exactly N soul gems by visiting exactly K nodes.
 

Input
First line contains an integer T, which indicates the number of test cases.

Every test case contains two integers N and K, which indicates soul gems the frog king want to collect and number of nodes he can visit.

 1T100.

 1N109.

 N2K260.
 

Output
For every test case, you should output "Case #x:" first, where x indicates the case number and counts from 1.

Then K lines follows, each line is formated as 'a b', where a is node label of the node the frog visited, and b is either '+' or '-' which means he increases / decreases his number by a.

It's guaranteed that there are at least one solution and if there are more than one solutions, you can output any of them.

 

Sample Input
25 310 4
 

Sample Output
Case #1:1 +3 -7 +Case #2:1 +3 +6 -12 +
 

Source
2015ACM/ICPC亚洲区上海站-重现赛(感谢华东理工)
 

好久没写博客了。。

一个构造题,重现的时候想炸了快,感觉每一点思路当时,但是有一种直觉就是:肯定是用2^0,2^1,2^2,...,2^(k-1)来构造,如果有差错的话,就在中间调整一步就可以了。事实证明这个直觉是对的。

有数据范围N<=2^k,可知,我们只需要
用二叉树的最左边一列k个(即从根节点一直向左走k层)即可,然后根据n的奇偶性判断是否要把最下的叶子节点2^k换成2^k+1.
因为最左列的和是sum=2^k-1,设d=sum-n,x=d/2,
这时只需要用2^0,2^1,2^2,..,2^(k-2)构造出x即可,然后构造x的这些个数取负就好了。
当然如果d是奇数的话,最后一个数取2^k+1,则sum变成sum=2^k,那么d=sum-n就又能保证是偶数了。


举个例子:k=4的话,sum=1+2+4+8=2^4-1=15。

n=3:d=sum-n=12,x=d/2=12/2=6,那么我们用2^0,2^1,2^2,..,2^(k-2)构造出6来就可以了,即选2和4,那么把2和4取负,其他的全正即可:3=1-2-4+8。

n=6:此时按上面的方法算出来的d=sum-n肯定不是偶数,为了能得到偶数,则sum应该变成sum=1+2+4+9=16.(即在最后一步向右,不走8,而走9),此时d=sum-n=16-6=10,

x=d/2=10/2=5.那么我们用2^0,2^1,2^2,..,2^(k-2)构造出5来就可以了,即选1和4,那么把1和4取负,其他的全正即可:6=-1+2-4+9。

至于为什么一定要保证d是偶数相信大家都能想明白。

/*****************PID:hdu5573*Auth:Jonariguez******************/#include <stdio.h>#include <string.h>#include <math.h>#include <vector>#include <algorithm>using namespace std;typedef long long LL;LL fact[65],bit[65],res[65];int sign[65];int main(){    LL i,j,n,k,T,kcase=1;    fact[1]=1;    for(i=2;i<=61;i++)        fact[i]=fact[i-1]*2;    scanf("%I64d",&T);    while(T--){        scanf("%I64d%I64d",&n,&k);        for(i=1;i<=k;i++){            res[i]=fact[i];sign[i]=1;        }        LL d=fact[k+1]-1-n;        if(n%2==0){            res[k]++;d++;        }        LL x=d/2,cnt=0;        while(x){            bit[cnt++]=x%2;x/=2;        }        for(i=1,j=0;j<cnt;j++){            if(bit[j]) sign[i]=0;            i++;        }        printf("Case #%I64d:\n",kcase++);        for(i=1;i<=k;i++){            printf("%I64d ",res[i]);            if(sign[i])                printf("+\n");            else printf("-\n");        }    }    return 0;}



2 0