之前在bc上做过一道类似的阶梯博弈的题目,那题是移动到根,这题是移动到叶子。换汤不换药,只要和终态不同奇偶的那些位置做nim即可。因此这题给出了一个条件:所有叶子深度的奇偶性相同。同时需要注意的是,上次bc中,根节点是不能移动的,因此根节点是终态节点,而这里叶子上面还可以进行操作(可以吃掉),那么就相当于叶子节点都还可以继续向下移动,因此他们不是终态节点,也就是说这题只要和叶子节点同奇偶的做nim即可。
因此,如果nim和已经是0,已经可以满足先手必输了,而题目说了必须要交换,那么只要让奇偶性相同的节点做交换即可,统计一下奇偶节点的个数再C(cnt, 2)就做完了;否则,后手必须要把和叶子节点不同奇偶的换过去来使得nim和为0,利用异或的性质以及map就可以做出来了。具体见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <vector> 6 #include <iostream> 7 using namespace std; 8 const int N = 1e5 + 5; 9 typedef long long ll; 10 11 int a[N]; 12 vector<int> G[N]; 13 int n; 14 int ji = -1; 15 void dfs(int u,int fa,int deep) 16 { 17 if(ji != -1) return ; 18 int flag = 0; 19 for(int i=0;i<G[u].size();i++) 20 { 21 int v = G[u][i]; 22 if(v != fa) 23 { 24 flag = 1; 25 dfs(v, u, deep + 1); 26 } 27 } 28 if(flag == 0) 29 { 30 ji = deep % 2; 31 } 32 } 33 vector<int> yes, no; 34 void dfs2(int u,int fa,int deep) 35 { 36 if(deep % 2 == ji) yes.push_back(a[u]); 37 else no.push_back(a[u]); 38 for(int i=0;i<G[u].size();i++) 39 { 40 int v = G[u][i]; 41 if(v != fa) 42 { 43 dfs2(v, u, deep + 1); 44 } 45 } 46 } 47 ll comb(int x) {if(x < 2) return 0; return (ll)x*(x-1) / 2;} 48 49 int main() 50 { 51 scanf("%d",&n); 52 for(int i=1;i<=n;i++) scanf("%d",a+i); 53 for(int i=2;i<=n;i++) 54 { 55 int v; 56 scanf("%d",&v); 57 G[i].push_back(v); 58 G[v].push_back(i); 59 } 60 dfs(1, -1, 1); 61 dfs2(1, -1, 1); 62 int temp = 0; 63 for(int i=0;i<yes.size();i++) temp ^= yes[i]; 64 if(temp == 0) 65 { 66 ll ans = comb(yes.size()) + comb(no.size()); 67 map<int,int> inyes; 68 for(int i=0;i<yes.size();i++) inyes[yes[i]]++; 69 for(int i=0;i<no.size();i++) ans += (ll)inyes[no[i]]; 70 cout << ans << endl; 71 } 72 else 73 { 74 ll ans = 0; 75 map<int,int> inno; 76 for(int i=0;i<no.size();i++) inno[no[i]]++; 77 for(int i=0;i<yes.size();i++) 78 { 79 ll t2 = temp ^ (yes[i]); 80 ans += inno[t2]; 81 } 82 cout << ans << endl; 83 } 84 return 0; 85 }