HDU 5573 Binary Tree ACM/ICPC 2015 Shanghai(构造)

来源:互联网 发布:c 游戏编程基础 编辑:程序博客网 时间:2024/05/21 14:41

Binary Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1482    Accepted Submission(s): 880
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, is1. 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 anotherN years, only if he could collect exactly N soul 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 nodex, 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 isN, 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, wherex 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亚洲区上海站-重现赛(感谢华东理工)



        现在想来非常简单的一道构造题。

        大致题意是给你一棵无穷大的满二叉树,其中任意节点i的两个儿子分别是2*i和2*i+1,然后每个节点的权值等于节点的编号。然后现在给你一个n和k,要你从根节点1开始,一直往下走选取k个节点,然后给每一个选取的点的点权加上正负,最后输出使得这k个节点的加权和为n的方案。只要求输出一种即可。

        看到这题,首先要联想到二进制的原理。我们知道,用二进制1、2、4、8、16……这些数字可以表示所有的数字,而在这个无穷大的满二叉树中,这些节点又全部存在,所以我们可以尝试利用这些数字。首先,由于题目满足一定有解,而且N<=2^k,所以我们一直都往左儿子走,这样和最大是2^k-1,当n比这个数字大的时候,左右一个数字我取2^(k-1)+1即可,所以说这么走总能有可行方案。然后,如果我们把这些数字全部用+连接记结果为sum,那么sum显然会大于等于n,当大于n的时候,我们就要把其中一些数字的权值变成其相反数。我们知道,原本是+的,现在要变成-,相当于在原来结果上,减去两遍。那么显然,减去的数字一定是偶数。所以说如果sum-n是奇数的时候,我们要考虑让sum加一,即可以对应最后一个数字取+1之后的数字。这样子的话,sum-n就是一个偶数,然后我们相当于只需要用1、2、4、8……这些数字,拼凑出一个(sum-n)/2即可,最后结果就是把拼凑(sum-n)/2的数字的符号变为-,其他的不变。具体见代码:

#include<bits/stdc++.h>#define INF 0x3f3f3f3f#define LL long long#define N 100010using namespace std;LL n,m,num[N];bool sign[N];int main(){    int T_T,T;    cin>>T_T;T=0;    while(T_T--)    {        scanf("%I64d%I64d",&n,&m);        LL i,j;        for(i=1,j=1;i<=m;i++,j<<=1)            num[i]=j,sign[i]=1;        LL x=j-1-n;        if (x&1) x++,num[m]++;        x>>=1;        for(;j;j>>=1,i--)            if (x>=j) sign[i]=0,x-=j;        printf("Case #%d:\n",++T);        for(int i=1;i<=m;i++)            printf("%I64d %c\n",num[i],sign[i]?'+':'-');    }    return 0;}

 

阅读全文
0 0