HazelFan wants to build a rooted tree. The tree has nn nodes labeled 0 to n?1, and the father of the node labeled i is the node labeled
. HazelFan wonders the size of every subtree, and you just need to tell him the XOR value of these answers.
Input
The first line contains a positive integer T(1≤T≤5)T(1≤T≤5), denoting the number of test cases.
For each test case:
A single line contains two positive integers n,k(1≤n,k≤1018)n,k(1≤n,k≤1018).
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.Sample Input
2 5 2 5 3
Sample Output
7 6 题意:画一下题目介绍的树,发现这是一个k叉树,那么题目要求所有子树大小的异或和。思路:我们从序号为n的节点开始,往上求异或和。n计算到某一层时,对于处在n节点左边的节点(子树),它们是t+1层的满k叉树,在右边的节点(子树)是t层的满二叉树,满二叉树的大小可以通过打表得到。根据异或计算的性质,大小相同的子树进行异或,有奇数个进行异或时结果为该子树的大小,偶数个时为0。而对n位置节点的子树来说,不是满二叉树就是非满二叉树,而且在计算这个子树大小时一旦它在某一层是非满二叉树,接下来往上它就一直是非满二叉树。还有,k==1时特判一下。具体实现参看代码。 AC代码:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; typedef long long LL; LL n, k; LL num[100]; int main() { int T; cin>>T; num[0]=1; while(T--) { scanf("%lld %lld", &n, &k); if(k==1){ if(n==1) printf("%d\n", 1); else if(n==2) printf("%d\n",3); else if(n==3) printf("%d\n", 0); else { int k=n%4; if(k==0) printf("%lld\n", n); else if(k==1) printf("%d\n", 1); else if(k==2) printf("%lld\n", n+1); else printf("%d\n", 0); } continue; } n--; int level=0,t=0; LL lm=0, rm=0; while(rm<n){ t++; lm=rm+1; rm=lm*k; num[t]=rm+1; } LL res=0,left,right,s=n+1,m; t=0; bool flag=0; LL mid=n%k;//mid判断是否为满k叉树, m为非满k叉树的大小 left=n-mid-lm+1; //cout<<left<<endl; if(left&1){ res^=num[0]; } if(mid&1) res^=num[0]; if(mid) flag=1; m=(n-(n-1)/k*k)*num[0]+1; //cout<<m<<endl; while(n) { //cout<<res<<‘*‘<<endl; t++; //cout<<t<<‘ ‘<<m<<endl; n=(n-1)/k; if(n<=0) break; mid=n%k; lm=(lm-1)/k; rm=(rm-1)/k; //cout<<lm<<‘ ‘<<n<<‘ ‘<<rm<<endl; right=rm-n; left=n-lm+1; if(flag||mid){ flag=1; left--; res^=m; } if(left&1) res^=num[t]; if(right&1) res^=num[t-1]; m+=(n-(n-1)/k*k-1)*num[t]+(((n-1)/k+1)*k-n)*num[t-1]+1; } res^=s; printf("%lld\n", res); } return 0; }
时间: 2024-10-12 00:04:03