题意:给权值n和步数k,
有一颗完全二叉树,第一个节点是1,他的左儿子就是i x 2,右儿子是i x 2+1
然后让你找到一个路径,使得通过加减恰好向下走k步之后,权值和为n
思路:贪心构造,观察一下会发现,叶子结点所在的一层的前两个叶子,往根部走,可以凑出来1~2*n-1所有的数,一列全是奇数,另一列全是偶数,不会存在找不到的情况。
怎么构造呢?
先找到叶子结点所在的数,令sum=t;
然后往根部走,如果sum>n,则下一个数取负的,累加到sum,如果sum<n,则下一个数取正,累加到sum,就可以了。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
using namespace std;
int main()
{
int i,j,k,p,t;
int n,m;
long long a;
long long b[100];
int c[100];
long long tot;
cin>>t;
for(p=1;p<=t;p++)
{
cin>>n>>k;
if(k==1)
printf("Case #%d: \n1 +\n",p);
else
{
printf("Case #%d: \n",p);
j=1;
if(n%2==1)
{
a=1;
for(i=1;i<k;i++)a*=2;
tot=a,b[1]=a,c[1]=1;
while(a>=1)
{
a/=2;
b[++j]=a;
if(tot>n)tot-=a,c[j]=0;
else tot+=a,c[j]=1;
}
}
else
{
a=1;
for(i=1;i<k;i++)a*=2;
a++;
tot=a,b[1]=a,c[1]=1;
while(a>=1)
{
a/=2;
b[++j]=a;
if(tot>n)tot-=a,c[j]=0;
else tot+=a,c[j]=1;
}
}
for(i=j-1;i>=1;i--)
{
printf("%lld ",b[i]);
if(c[i])printf("+\n");
else printf("-\n");
}
}
}
return 0;
}