1. 程式人生 > >Binary Tree (構造)

Binary Tree (構造)

The Old Frog King lives on the root of an infinite tree. According to the law, each node should connect
to exactly two nodes on the next level, forming a full binary tree.
Since the king is professional in math, he sets a number to each node. Specifically, the root of the
tree, where the King lives, is 1. Say froot = 1.
And for each node u, labels as fu, the left child is fu × 2 and right child is fu × 2 + 1. The king
looks at his tree kingdom, and feels satisfied.
Time flies, and the frog king gets sick. According to the old dark magic, there is a way for the king
to live for another N years, only if he could collect exactly N soul gems.
Initially the king has zero soul gems, and he is now at the root. He will walk down, choosing left or
right child to continue. Each time at node x, the number at the node is fx (remember froot = 1), he
can choose to increase his number of soul gem by fx, or decrease it by fx.
He will walk from the root, visit exactly K nodes (including the root), and do the increasement or
decreasement as told. If at last the number is N, then he will succeed.
Noting as the soul gem is some kind of magic, the number of soul gems the king has could be
negative.
Given N, K, help the King find a way to collect exactly N soul gems by visiting exactly K nodes.
Input
First line contains an integer T, which indicates the number of test cases.
Every test case contains two integers N and K, which indicates soul gems the frog king want to
collect and number of nodes he can visit.
Restrictions:
• 1 ≤ T ≤ 100.
• 1 ≤ N ≤ 109
.
• N ≤ 2
K ≤ 2
60
.
Output
For every test case, you should output ‘Case #x:’ first, where x indicates the case number and counts
from 1.
Then K lines follows, each line is formated as ‘a b’, where a is node label of the node the frog visited,
and b is either ‘+’ or ‘-’ which means he increases / decreases his number by a.
It’s guaranteed that there are at least one solution and if there are more than one solutions, you
can output any of them.
Sample Input
2
5 3
10 4
Sample Output
Case #1:
1 +
3 -
7 +
Case #2:
1 +
3 +
6 -
12 +

題目大概:

給你一棵二叉樹,二叉樹按行標號,然後標號就是二叉樹的權值,給你一個數n,一個數k,讓你用k層二叉樹來構造出一個數n,必須一直向深處走,不能回頭走,每到一個節點,可以加權值,也可以減權值。給出一種構造方案。

思路:

看到構造數n,然後二叉樹的最左邊又都是二進位制數,很容易想到二進位制數可以構造任何一個數。然後,這裡不是能選和不能選,而是加和減,這就和我們的期望不一樣了。

這樣就想要讓這些二進位制數來加減抵消,來湊出這個n。然後可以先把最左邊的二進位制數求和為sum,然後sum-n。就得到了需要加減抵消的數,然後除2,就是需要是負數的數,直接從大到小暴力構造這個負數就行了。這樣就只需要用左邊這一樣就能構造出n,但是當sum-n是奇數的時候,就需要+1,來使得剛好抵消,這樣最後一個數就不能選擇最左邊的數,就需要右移一位。

程式碼:

#include<bits/stdc++.h>

using namespace std;
#define ll long long

const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
int n,k;
ll p[100];
int ans=0;
void init()
{
    ll sum_1=1;
    p[ans++]=sum_1;
    for(int i=1;i<=60;i++)
    {
        sum_1*=2;
        p[ans++]=sum_1;
    }
}
int vis[100];

int main()
{
    int t;
    int tem=1;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        memset(vis,0,sizeof(vis));
        ll sum=p[k]-1;
        sum-=n;
        int flag=0;
        if(sum%2==1)
        {
            sum++;
            flag=1;
        }

        sum/=2;
        for(int i=k-1;i>=0;i--)
        {
            if(sum>=p[i])
            {
                sum-=p[i];
                vis[i]=1;
            }
        }
        printf("Case #%d:\n",tem++);
        for(int i=0;i<k-1;i++)
        {
            if(vis[i])
            {
                printf("%lld -\n",p[i]);
            }
            else
            {
                printf("%lld +\n",p[i]);
            }
        }
        if(flag)
        {
            printf("%lld +\n",p[k-1]+1);
        }
        else
        {
            printf("%lld +\n",p[k-1]);
        }
    }
    return 0;
}