1. 程式人生 > >2015上海現場賽 HDU 5573

2015上海現場賽 HDU 5573

這是一道在克隆賽碰到的題,當時看題隊友以為是樹形dp或者是暴搜,想了一下都沒有思路,其實是一道 " 思維+二進位制 "。

 

題目連結:傳送門

 

題意:給你一棵有K層的滿二叉樹,讓你從根節點開始走(根節點為1),經過K個節點(包括根節點),走到葉子節點,途中經過節點的值,利用加減組成N,並按順序輸出。

 

我們多試幾組資料,我們會發現一個特點,二叉樹最左側的值能夠組成所有值,最左側k-1層的結點之和為sum=(1<<(k-1))-1,sum肯定是一個奇數,如果n為偶數的話,我們第k層的節點選取左側節點,sum=sum+(1<<(k-1)+1),否則就選取右側節點,sum=sum+(1<<(k-1))。現在數字已經確定了,就差符號沒有確定。

我們知道sum肯定是大於等於n的,sum和n的差值為d,d=sum-n。//因為 sum 和 n 同奇偶,所以d是一個偶數。

n + d = sum    —>    n + d/2 + d/2 = sum   —>  n + d/2 -d/2 = sum - d;

我們找出的 d/2 就是需要減掉的部分,利用二進位制的位運算,如果某一位為1就是減號這個數,否則就是加號(二叉樹最左側都是2次冪的數)

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int t;
    scanf("%d",&t);
    for(int u=1;u<=t;u++)
    {
        ll n,k,sum;
        scanf("%lld %lld",&n,&k);
        printf("Case #%d:\n",u);
        queue<ll>q;
        for(int i=0;i<k-1;i++)
            q.push(1<<i);       ///先將k-1層的節點值放進佇列。
        sum=(1<<k)-1;
        if((sum&1)==(n&1))      ///判斷奇偶確定k層節點的值。
            q.push(1<<(k-1));
        else
        {
            sum++;
            q.push((1<<(k-1))+1);
        }
        ll d=(sum-n)>>1;        ///確定加減。
        while(q.size())
        {
            if(d&1) cout<<q.front()<<" -"<<endl;
            else    cout<<q.front()<<" +"<<endl;
            d=d>>1;
            q.pop();
        }
    }
    return 0;
}