题目连接:题目
大意:
有一颗完全二叉树,第一个节点是1,他的左儿子就是i x 2,右儿子是i x 2+1
然后让你找到一个路径,使得通过加减恰好向下走k步之后,权值和为n,
解题思路:
构造题
首先我们可以分析得到,所有答案都可以通过走 1,2,4,8,16.....来得到
为什么?因为n<=2^k.
如果是奇数,那么我们最后一步就选左儿子,否则选择右儿子
路径问题解决了,我们就差符号问题了
符号问题,我们就可以通过找规律来解决
比如 n的二进制为100101
那么我们k步的符号就可以是110010(1表示+,0表示-)
就第一个位置是1,其他位置都是0就好了
比如001,你可以通过4-2-1来构造出来,就是001->100
--------------------
构造题好费脑
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
long long n,k;
int flag=0;
int a[100+10];
int main(int argc, char const *argv[])
{
int t;scanf("%d",&t);
for(int p=1;p<=t;p++){
scanf("%lld%lld",&n,&k);
flag=0;
memset(a,0,sizeof(a));
if(n%2==0){ //构造奇数
flag=1;
n=n-1;
}
int tmp=0;
for(int i=k-1;i>=0;i--){
a[i]=1-tmp;
tmp=1;
if((n>>i)&1)
{
tmp=0;
printf("%d %d\n",(n>>i)&1,i);
}
}
printf("Case #%d:\n",p);
long long now = 1;
for(int i=0;i<k-1;i++){
printf("%lld ",now);
now = now*2;
if(a[i]) printf("+\n");
else printf("-\n");
}
if(flag) printf("%lld ",now+1);
else printf("%lld ",now);
if(a[k-1]) printf("+\n");
else printf("-\n");
}
return 0;
}