標籤:蘋果 val test 遊戲 stream i++ lan iostream 連結
題目連結:http://codeforces.com/contest/812/problem/E
題意:有一顆蘋果樹,這個蘋果樹所有葉子節點的深度要不全是奇數,要不全是偶數,並且包括根在內的所有節點上都有若干個蘋果,現有兩個,每個人可以吃掉某個葉子節點上的部分蘋果(不能不吃),或者將某個非葉子結點上的部分蘋果移向它的孩子(當然也不能不移),吃掉樹上最後一個蘋果的人獲勝。後手可以在遊戲開始之前交換任意兩個不同的節點的蘋果,輸出交換後能使得後手勝利的交換總數。
題解:這題挺友善的所有葉子結點的深度奇偶性是一樣的,首先考慮到葉子結點是奇數步的,顯然不論先手怎麼操作,後手總是能吃掉這些蘋果比較顯然不解釋了。然後就是偶數步時,先手操作一次偶數步時顯然偶數步就會變成奇數步,也就是說移動的這部分蘋果肯定是先手吃到的。於是就轉換到了裸的尼姆博弈,什麼是尼姆博弈不知道的可以去百度一下。於是這題只要將所有偶數步的節點上的蘋果異或一下如果結果是0那麼後手勝利否則先手勝利。
然後就是怎麼處理交換了,如果ans=0(ans表示異或結果)那麼只要在偶數步與奇數步中交換相同的數即可,還有就是偶數步中與奇數步中分別自行交換。
如果ans!=0那麼只要遍曆一遍偶數步的點找奇數點中蘋果數為ans^val[i]的個數即可。
#include <iostream>#include <string>#include <cstdio>#include <map>#include <vector>using namespace std;typedef long long ll;const int M = 1e5 + 10;map<int , int>num;vector<int>vc[M];int ans , val[M] , deep[M] , maxdeep;void dfs(int u , int pre , int d) { int len = vc[u].size(); deep[u] = d; maxdeep = max(maxdeep , d); for(int i = 0 ; i < len ; i++) { int v = vc[u][i]; if(v == pre) continue; dfs(v , u , d + 1); }}int main() { int n; scanf("%d" , &n); num.clear(); for(int i = 0 ; i <= n ; i++) vc[i].clear(); for(int i = 1 ; i <= n ; i++) { int gg; scanf("%d" , &gg); val[i] = gg; num[gg]++; } for(int i = 1 ; i < n ; i++) { int gg; scanf("%d" , &gg); vc[gg].push_back(i + 1); vc[i + 1].push_back(gg); } maxdeep = 0; dfs(1 , -1 , 1); for(int i = 1 ; i <= n ; i++) { if((maxdeep % 2) == (deep[i] % 2)) { num[val[i]]-- , ans ^= val[i]; } }//這裡處理奇數偶數步用了取巧的方法。就是如果奇偶性和最大深度的奇偶性相同那麼就必定是偶數點 ll count = 0; if(ans == 0) { ll sum = 0; for(int i = 1 ; i <= n ; i++) { if((maxdeep % 2) == (deep[i] % 2)) { count += num[val[i]]; } else sum++; } count += (sum * (sum - 1) / 2 + (n - sum) * (n - sum - 1) / 2); } else { for(int i = 1 ; i <= n ; i++) { if((maxdeep % 2) == (deep[i] % 2)) { count += num[(ans ^ val[i])]; } } } printf("%lld\n" , count); return 0;}
codeforces 812 E. Sagheer and Apple Tree(樹+尼姆博弈)