http://acm.hdu.edu.cn/showproblem.php?pid=6121
题意:
给你一颗完全K叉树,求出每棵子树的节点个数的异或和。
思路:
首先需要了解一些关于完全K叉树或满K叉树的一些知识:
对于每棵子树,只有三种情况:
①是满K叉树 ②不是满K叉树 ③叶子节点
并且非满K叉树最多只有一个,所以只需要将它进行特殊处理,具体看代码吧,说不清楚。代码参考了http://blog.csdn.net/my_sunshine26/article/details/77200282。
当K=1时,树是链状的,需要打表找规律!
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn=100+5; 17 18 ll n, k, ans; 19 ll num[maxn]; 20 int depth; 21 22 void init() 23 { 24 num[0]=0; 25 for(int i=1;i<=depth;i++) 26 { 27 num[i]=num[i-1]+pow((long double)k,(long double)i-1); //因为pow默认是pow(int,int),没有对应long long的,所以我这儿用long double来代替了一下 28 } //当然这里可以自己用快速幂来计算 29 } 30 31 int main() 32 { 33 //freopen("in.txt","r",stdin); 34 int T; 35 scanf("%d",&T); 36 while(T--) 37 { 38 scanf("%I64d%I64d",&n,&k); 39 if(k==1) //特判 40 { 41 ll tmp=n%4; 42 if(tmp==0) ans=n; 43 else if(tmp==1) ans=1; 44 else if(tmp==2) ans=n+1; 45 else ans=0; 46 printf("%I64d\n",ans); 47 continue; 48 } 49 50 depth=1; 51 ll tmp=n-1; 52 //计算树的深度 53 while(tmp>0) 54 { 55 tmp=(tmp-1)/k; 56 depth++; 57 } 58 init(); //预处理前i层的节点个数 59 ans=0; 60 ans^=(n-num[depth-1])&1; //先处理一下最后一层 61 depth--; 62 ll now=2; //当前从下往上第几层 63 ll pos=(n-1-1)/k; 64 while(depth>0) 65 { 66 ll left=num[depth-1]; //当前层数最左边编号 67 ll right=num[depth]-1; //当前层数最右边编号 68 ll tmp1=num[now]; //左边树大小 69 ll tmp2=num[now-1]; //右边树大小 70 71 //奇数才有贡献 72 if((pos-left)&1) ans^=tmp1; 73 if((right-pos)&1) ans^=tmp2; 74 75 ll cnt=pos; 76 while(cnt<=(n-1-1)/k) cnt=cnt*k+1; 77 ans^=(num[now-1]+n-cnt); //单独处理临界点子树 78 now++; 79 depth--; 80 pos=(pos-1)/k; 81 82 } 83 printf("%I64d\n",ans); 84 } 85 return 0; 86 }
时间: 2024-11-02 23:30:41