Binary Tree HDU - 5573

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82379308

Binary Tree

题目链接:HDU - 5573

题意:一个无穷大的完全二叉树,每个节点的值由上到下,由左到右依次为1, 2, 3, 4, 5, ......;现在给出一个数n,要求走k步,每到达一个节点可以选择加这个点的值或者减这个点的值,初始值为0,第一步永远在根节点1,且只能向下走,最终停下后得到的值恰好等于n;

思路:对于这个二叉树来说,最左侧是2^0, 2^1, 2^2, 2^3, ... , 2^m, ...;走k步一定到达第k行对于前k行的最左侧最大得到的值为:sum=2^0+2^1+2^2+...+2^(k-1)=2^k  -  1;  =如果只是任选这k个数一定能得到1~2^k - 1中的任意一个数,现在的问题是所有数都要选,可加可减,要构造出一个n,那么我们可以先构造一个sum-n,然后再用sum减去就可以了;另外,这样似乎冥冥之中有点不妥,那里有毛病呢???当构造出sum-n之后,身下的数加起来就不再是sum了;所以就不可行了;但是大体方向是没有错的,现在只是要把思维再发散一下;

令d=sum-n; 得到n=sum-d=sum-d/2-d/2=(sum-d/2)-d/2;观察一下这个式子,将其看做两部分,d/2是我们要构造出来的数,去掉这个数后剩下的数的和就是sum-d/2;这样一来就得到了n;这下子思路就顺畅了许多,我们要先构造出一个d/2,这是要减掉的,然后剩下的加起来就得到n了;但是这里的d只能是偶数才行;而sum必定是奇数无疑了,所以这个推导只适合n是奇数的情况;那么当n是偶数是我们需要将sum也变为偶数,直接加1就可以了;,这个1是哪里来的呢?第k行将2^(k-1)该选为2^(k-1)+1就可以了,此时sum=2^k  -1  + 1=2^k;

现在理一下思路:

当n为奇数时,选2^0, 2^1, ... , 2^(k-1),sum=2^k - 1,然后在这些数中选若干数构造一个(sum-n)/2,选中的数进行减操作,未选中的数进行加操作;

当n为偶数是,选2^0, 2^1, ... , 2^(k-2), 2^(k-1)+1, sum=2^k, 然后在前k-1个数中选若干数,构造一个(sum-n)/2,选中的数进行减操作,剩下的数进行加操作;

还有一个小问题,怎么构造(sum-n)/2? 这就很简单啦,选其二进制位上为1的数,加起来就是了;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[62];
void init(){
	f[0]=1LL;
	for(int i=1; i<=60; i++){
		f[i]=f[i-1]<<1LL;
	}
}
int main(){
	int T, cas=0;
	scanf("%d", &T);
	init();
	while(T--){
		ll n;
		int k;
		scanf("%lld%d", &n, &k);
		ll sum, d, x;
		if(n&1) sum=f[k]-1;
		else sum=f[k];
		x=(sum-n)/2;
		int cnt=0;
		printf("Case #%d:\n", ++cas);
		while(cnt<k){
				if(cnt==k-1) printf("%lld ", f[cnt]+((n&1)==0?1:0));
			else printf("%lld ", f[cnt]);
			if(x&1) puts("-");
			else puts("+");
			cnt++;
			x>>=1;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/82379308
今日推荐