hdu5573 Binary Tree (构造)

题目:

一棵二叉树,根节点是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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值