1. 程式人生 > >Codeforces 812E(Nim變形)

Codeforces 812E(Nim變形)

必須 現在 ces 異或 技術 () names %d spa

題意:一棵樹(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 }
Psong

Codeforces 812E(Nim變形)