题意:询问n个点的完全k叉树,所有子树节点个数的异或总和为多少。
题解:对于树的每一层,我们可以分为三种节点,①满节点的k叉树②不满的k叉树③比第一种情况少一层的满节点的k叉树,然后从叶子节点开始不断转移到上一层。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
long long fac[105];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
long long n,k;
scanf("%lld%lld",&n,&k);
fac[1]=1;
for(int i=2; i<=70; i++)
fac[i]=fac[i-1]*k;
if(k==1)
{
if(n%4==0)
printf("%lld\n",n);
if(n%4==1)
printf("1\n");
if(n%4==2)
printf("%lld\n",n+1);
if(n%4==3)
printf("0\n");
continue;
}
if(n==1)
{
printf("1\n");
continue;
}
int h=1;
long long base=1;
long long res=n-1;
while(res>0)
{
h++;
if((res/k)>=base)
{
base*=k;
res-=base;
}
else
break;
}
long long ans=0;
if(res%2==1)
ans^=1;
long long lt,mid,rt;
long long slt,smid,srt;
lt=(res-1)/k;
mid=1;
rt=fac[h-1]-mid-lt;
slt=k+1;
smid=res-k*lt+1;
srt=1;
for(int i=h-1;i>=1;i--)
{
if(lt%2==1)
ans^=slt;
ans^=smid;
if(rt%2==1)
ans^=srt;
long long tpl=lt;
long long tpr=rt;
lt=lt/k;
rt=rt/k;
mid=1;
tpl=tpl-lt*k;
tpr=tpr-rt*k;
smid=tpl*slt+tpr*srt+smid+1;
slt=slt*k+1;
srt=srt*k+1;
}
printf("%lld\n",ans);
}
}