给你n,K,让你构造出一颗n个结点的完全K叉树,求所有结点子树大小的异或和。
先把n号结点到根的路径提取出来单独计算。然后这条路径把每一层分成了左右两部分,每一层的左侧和其上一层的右侧的结点的子树大小相同。
就可以容易计算每种大小的子树个数了。
当K等于1时,要单独讨论,答案为1 xor 2 xor ... xor n。这个打个表非常明显。
#include<cstdio> using namespace std; typedef long long ll; ll n,K,pw[105]; int T; int main(){ // freopen("1002.in","r",stdin); // freopen("1002.out","w",stdout); scanf("%d",&T); for(;T;--T){ scanf("%lld%lld",&n,&K); if(K==1){ if(n%4ll==0){ printf("%lld\n",n); } else if(n%4ll==1ll){ printf("%lld\n",1ll); } else if(n%4ll==2ll){ printf("%lld\n",n+1ll); } else{ printf("%lld\n",0ll); } continue; } pw[0]=1; int j; for(j=1;pw[j-1]<=n/K;++j){ pw[j]=pw[j-1]*K; } --j; int e=j; for(int k=1;k<=j;++k){ if(pw[k-1]>n-pw[k]){ e=k-1; break; } pw[k]+=pw[k-1]; } if(n==pw[e]){ --e; } ll i=n-1ll; ll now=n; ll nowsiz=1,sumnowsiz=1; ll ans=1; ll sheng=((n-pw[e])%K!=0 ? (n-pw[e])%K : K); int E=e; while(i!=0){ ll fa=(i-1)/K; if((i-1ll-fa)%2ll==1ll){ ans^=sumnowsiz; } ans^=(sumnowsiz+sheng); now=pw[e]; --e; i=fa; nowsiz*=K; sumnowsiz+=nowsiz; sheng=((n-pw[E])%(nowsiz*K)!=0 ? (n-pw[E])%(nowsiz*K) : (nowsiz*K)); } printf("%lld\n",ans); } return 0; }
时间: 2024-10-13 13:52:10