HDU - 5573 Binary Tree(思维+构造+二进制)

题目链接:点击查看

题目大意:给出一棵无限大的完全二叉树,每次给出一个 n 和一个 k ,要求从点 1 出发一直向下,找到一条长度为 k 的路径,对于路径上的点可以加上其编号,也可以减去其编号,需要构造出一种方案,使得计算的结果为 n

题目分析:因为 k 最大只有 60 ,给足了提示是需要往二进制上思考,但奈何对二进制的题目不太敏感,之前打 cf 时碰到的二进制题目也是因为不会做无奈只能掉分。。菜啊

回到这个题目,稍微画几层这个完全二叉树,不难发现最左边的一条链上恰好是二进制数,也就是 1 , 2 , 4 , 8 ... ,因为题目保证了 n <= 2^k,所以最左边一条链之和我们记为 sum,一定有 sum >= n 

所以我们完全可以选择最左边的这条链,然后在适当的位置将正号变为负号即可,考虑变号的影响,对于一个位置 x ,原本 sum = 1 + 2 + 4 + ... + x + ... + 2^k, 现在如果将 x 前面的正号变为负号,其影响是 1 + 2 + 4 + ... - x + ... + 2^k = sum - 2 * x

可以看到,如果将一个位置的正号变为负号,总的 sum 会减少其两倍的贡献,换一种思想,如果我们想要让 sum 减少 x ( x 为偶数 )的话,那么我们只需要将编号为 x/2 的节点变号即可

接下来我们设置变量 delta = sum - n ,也就是说我们只需要将最左边的这条链,减少 delta 的量,就可以让其计算的结果等于 n 了,如果 delta 为偶数的话,上文也提到了,直接将其除以 2 ,然后找到相应的位置变号即可

现在考虑如果 delta 为奇数该如何处理,这个时候我们只需要在第 k - 1 层到达第 k 层时,遍历其右儿子而不是其左儿子就可以了,这样的话 sum 就变成了 sum + 1,此时再去计算 delta 的话就是偶数了,处理方法同上

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=2e5+100;

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	int kase=0;
	while(w--)
	{
		LL n,k;
		scanf("%lld%lld",&n,&k);
		LL sum=(1<<k)-1;
		LL delta=sum-n;
		bool flag=(delta&1);
		delta=(delta+1)/2;
		printf("Case #%d:\n",++kase);
		for(int i=0;i<k-1;i++)
		{
			if((delta>>i)&1)
				printf("%lld -\n",1LL<<i);
			else
				printf("%lld +\n",1LL<<i);
		}
		if(flag)
			printf("%lld +\n",(1LL<<k-1)+1);
		else
			printf("%lld +\n",1LL<<k-1);
	}











   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108354268