Codeforces 812E(Nim变形)
Posted Psong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 812E(Nim变形)相关的知识,希望对你有一定的参考价值。
题意:一棵树(1为根,所有叶子节点深度同奇偶),每个节点上有一些苹果。现有两种操作:1.吃掉叶子节点上的苹果;2.将非叶子节点上的苹果送给儿子节点。两人轮流操作,无法操作的人输,现在后手玩家可以任意交换两个节点的苹果数,问有多少种交换方法使得后手胜利(必须交换)。
题解:将所有节点分为两类,深度与叶子节点同奇偶(蓝)、深度与叶子节点奇偶不同(红)。有结论:当所有蓝色节点异或和为 0 时,后手必胜。因此需要寻找有多少种交换方法可以使得蓝色节点异或和为0。
证明:可以将所有的蓝色节点看作Nim游戏中的石堆,现在的操作可以放入(将红色节点的苹果送给蓝色儿子)也可以拿出(吃掉蓝色叶子结点的苹果 or 将蓝色节点的苹果送给红色儿子)。因此结论与Nim相同:蓝色节点异或和为 0 时,后手必胜。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 int n,s,p; 5 int a[100005]; 6 int in[100005]; 7 int vis[100005]; 8 vector<int> v[2]; 9 map<int,int> num[2]; 10 vector<int> g[100005]; 11 int dfs(int u,int deep){ 12 vis[u]=(deep%2); 13 v[deep%2].push_back(a[u]); 14 num[deep%2][a[u]]++; 15 for(int i=0;i<g[u].size();i++){ 16 dfs(g[u][i],deep+1); 17 } 18 } 19 int main(){ 20 s=0; 21 scanf("%d",&n); 22 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 23 for(int i=2;i<=n;i++){ 24 scanf("%d",&p); 25 g[p].push_back(i); 26 in[p]++; 27 } 28 dfs(1,0); 29 int p=-1; 30 for(int i=1;i<=n;i++){ 31 if(in[i]==0){ 32 p=vis[i]; 33 break; 34 } 35 } 36 for(int i=0;i<v[p].size();i++) s^=v[p][i]; 37 LL ans=0; 38 if(s==0){ 39 LL l1=v[0].size(),l2=v[1].size(); 40 ans+=l1*(l1-1)/2+l2*(l2-1)/2; 41 for(int i=0;i<v[p].size();i++){ 42 int tmp=v[p][i]; 43 ans+=(LL)num[p][tmp]*num[1-p][tmp]; 44 num[p][tmp]=num[1-p][tmp]=0; 45 } 46 } 47 else{ 48 for(int i=0;i<v[p].size();i++){ 49 int tmp=s^v[p][i]; 50 ans+=(LL)num[p][v[p][i]]*num[1-p][tmp]; 51 num[p][v[p][i]]=num[1-p][tmp]=0; 52 } 53 } 54 printf("%lld\n",ans); 55 56 return 0; 57 }
以上是关于Codeforces 812E(Nim变形)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 812E Sagheer and Apple Tree ——(阶梯博弈)