hdu5573 Binary Tree (构造)

来源:互联网 发布:java开发界面化软件 编辑:程序博客网 时间:2024/04/30 11:58

题目:

一棵二叉树,根节点是1,往后依次左节点是2*i, 右节点是2* i+1。现从根节点开始往下走,走k个节点,每个节点可取正数或负数,问能否求和凑出n?
1N109
N2k260

分析:

因为还要输出路径,和每个数取正还是取负,就感觉应该是个构造或找规律的题,否则不好记录路径。又有N2k,这句话限制了层数,比如想凑10,1+3+6可以凑出来,只用了3层,但是这是不可以的因为2^3=8,只能用4层。多少可以获得一些启发。
构造方法如下:我们知道前k层的第一个数,20,21,22...2k,可以凑出来2k+11范围内的所有数字。这个数字肯定大于n,现在就让其中某些数字取负,使得和正好等于n。若一个数k取负,那么总和是少了2*k的。所以我们求出差:sum=(2k+11)n,因为一个数取负会少2倍,所以那些取负的数字和应该是d=sum/2。前k-1层的第一个数可以凑出2k1内的任意数,所以d是肯定能凑出来的。
考虑一个问题,假如sum是偶数,那么毫无问题,直接凑出d即可。
若sum是奇数,那么我们让sum+1变偶数,然后再正常去掉d,但是这样我们去掉了(sum+1),多去了1,怎么办?只需要让最后一个节点走的时候走到右儿子即可。

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <queue>#include <stack>#include <set>#include <map>#include <algorithm>using namespace std;#define ms(a,b) memset(a,b,sizeof(a))const int inf = 0x3f3f3f3f;int n, k, sign[65];int main(){    int t;    scanf("%d", &t);    for(int tt=1;tt<=t;tt++){        ms(sign, 0); // 0是+        scanf("%d%d", &n, &k);        long long tmp = ((long long)1 << k)-1-n;        int flag = 0;        if(tmp&1){            tmp++;            flag = 1;        }        for(int i=1;i<=k;i++){            sign[i] = (tmp>>i)&1;        }        printf("Case #%d:\n", tt);        for(int i=1;i<=k-1;i++){            printf("%d %c\n", (1<<(i-1)), sign[i] ? '-':'+');        }        if(!flag){            printf("%d +\n", (1<<(k-1)));        }        else{            printf("%d +\n", (1<<(k-1))+1);        }    }    return 0;}