hdu6121 Build a tree(好题)

题意:

给你一个有n个结点的完全K叉树,求每个子树的节点数量,并将他们异或输出。

思路:

从倒数第二层开始,找出其中的非满k叉树(每一层最多只有一个),其左边是now层的满K叉树,其右边是now-1层的满K叉树,再根据数量来分别决定是否异或其层数。然后在异或上当前非满K叉树。最后去到倒数i+1层,逐层判断即可,k>1时最多有59层,k=1时打表找规律··。

代码:

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long ll;
ll num[60];
int init(ll n,ll k)
{
    num[1] = 1;
    int i;
    for(i = 2;i<60;i++)
    {
        num[i] = num[i-1]*k+1;
        if(num[i]>=n)
            break;
    }
    return i;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll n,k;
        scanf("%lld%lld",&n,&k);
        if(k==1)
            printf("%lld\n",n%4==0?n:(n%4==1?1:(n%4==2?n+1:0)));
        else
        {
            int depth = init(n,k); //初始化k叉树前i层节点数,并得到总层数
            //cout<<depth<<endl;
            depth--;
            int now = 2; //倒数第几层
            ll pos = (n-2)/k;//非满二叉树的位置
            ll ans = n;
            if((n-num[depth])&1)
                ans ^= 1;
            while(depth>1)
            {
                ll ml = num[depth-1];
                ll mr = num[depth]-1;
                ll temp1 = num[now];
                ll temp2 = num[now-1];
                if((pos-ml)&1)
                    ans^=temp1;
                if((mr-pos)&1)
                    ans^=temp2;
                ll cnt = pos;
                while(cnt<=(n-2)/k)   //直接判断cnt*k+1<=n-1会爆long long, 变除法时尽量凑出等号,不然会WA
                    cnt = cnt*k+1;
                ans ^= num[now-1]+n-cnt;
                now++;
                depth--;
                pos = (pos-1)/k;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值