HDU 6121 Build a tree(递归)

来源:互联网 发布:vrp在线算法 编辑:程序博客网 时间:2024/05/17 22:28

Description

给出一个满k叉树的点数n,第i个点的父亲是i1k ,第i个点的权值为以该点为根的子树点数,问这n个点的权值异或和

Input

第一行一整数T表示用例组数,每组用例输入两个整数nk(1T5,1n,k1018)

Output

输出n个点权值异或和

Sample Input

2
5 2
5 3

Sample Output

7
6

Solution

找到不完全的子树,该子树左边的兄弟子树和右边的兄弟子树都是完全k叉树,其权值异或和很好计算,解决了这些兄弟和根后,递归到该子树中进行同样的操作直至树的深度为2时可以快速得到答案

注意k=1时要特判,此时ans=1 Xor 2 Xor .... Xor n

Code

#include<cstdio>using namespace std;typedef long long ll;ll n,k;ll Solve(){    if(n<k+1)    {        if(n&1)return n;        return n+1;    }    ll Sum=1,p=1,Xor=1;    while((n-Sum)/k>=p)    {        p*=k;        Sum+=p;        Xor^=p;    }    ll L=(n-Sum-1)/p,R=k-L-1;    ll ans=n;    if(k&1)    {        if(L&1)ans^=Xor;        if(R&1)ans^=(Xor^p);    }    else    {        if(L&1)ans^=Sum;        if(R&1)ans^=(Sum-p);    }    n-=L*Sum+R*(Sum-p)+1;    return ans^Solve();}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%I64d%I64d",&n,&k);        if(k==1)        {            if(n%4==0)printf("%I64d\n",n);            else if(n%4==1)printf("1\n");            else if(n%4==2)printf("%I64d\n",n+1);            else printf("0\n");        }        else        {            printf("%I64d\n",Solve());        }    }    return 0;}