Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈)
Codeforces Round #417:E. FountainsSagheer and Apple Tree(樹上博弈)
標(biāo)簽:?codeforces 2017-06-02 11:41?29人閱讀?評論(0)?收藏?舉報 ?分類:版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
E. Sagheer and Apple Tree time limit per test ?2 seconds memory limit per test ?256 megabytes input ?standard input output ?standard output
Sagheer is playing a game with his best friend Soliman. He brought a tree with?n?nodes numbered from?1?to?n?and rooted at node?1. The?i-th node has?ai?apples. This tree has a special property: the lengths of all paths from the root to any leaf have the same parity (i.e. all paths have even length or all paths have odd length).
Sagheer and Soliman will take turns to play. Soliman will make the first move. The player who can't make a move loses.
In each move, the current player will pick a single node, take a non-empty subset of apples from it and do one of the following two things:
- eat the apples, if the node is a leaf.
- move the apples to one of the children, if the node is non-leaf.
Before Soliman comes to start playing, Sagheer will make?exactly one change?to the tree. He will pick two different nodes?u?and?v?and swap the apples of?u?with the apples of?v.
Can you help Sagheer count the number of ways to make the swap (i.e. to choose?u?and?v) after which he will win the game if both players play optimally??(u,?v)?and?(v,?u)?are considered to be the same pair.
InputThe first line will contain one integer?n?(2?≤?n?≤?105)?— the number of nodes in the apple tree.
The second line will contain?n?integers?a1,?a2,?...,?an?(1?≤?ai?≤?107) — the number of apples on each node of the tree.
The third line will contain?n?-?1?integers?p2,?p3,?...,?pn?(1?≤?pi?≤?n) — the parent of each node of the tree. Node?i?has parent?pi?(for?2?≤?i?≤?n). Node?1?is the root of the tree.
It is guaranteed that the input describes a valid tree, and the lengths of all paths from the root to any leaf will have the same parity.
OutputOn a single line, print the number of different pairs of nodes?(u,?v),?u?≠?v?such that if they start playing after swapping the apples of both nodes, Sagheer will win the game.?(u,?v)?and?(v,?u)?are considered to be the same pair.
Examples input3 2 2 3 1 1output
1input
3 1 2 3 1 1output
0input
8 7 2 2 5 4 3 1 1 1 1 1 4 4 5 6output
4
題意:
有一顆很奇怪的蘋果樹,這個蘋果樹所有葉子節(jié)點的深度要不全是奇數(shù),要不全是偶數(shù),并且包括根在內(nèi)的所有節(jié)點上都有若干個蘋果,現(xiàn)有兩個極其聰明的人又來無聊的游戲了,每個人可以吃掉某個葉子節(jié)點上的部分蘋果(不能不吃),或者將某個非葉子結(jié)點上的部分蘋果移向它的孩子(當(dāng)然也不能不移),吃掉樹上最后一個蘋果的人獲勝,問先手是否必勝?不,不是問這個,因為后手可以作弊,他可以交換任意兩個節(jié)點的蘋果數(shù)量,問有多少種不同的作弊(交換)方式可以使得后手必勝(不能不交換)?
樹上尼姆:
不如考慮什么時候先手必勝,在尼姆博弈中,將所有的蘋果個數(shù)依次異或,如果最后答案為0就先手必敗,否則必勝,那么樹上的呢?其實一樣,不妨把節(jié)點按照深度分成兩種:①想要移動到任意葉子結(jié)點都需要偶數(shù)步數(shù)(深度和最深的葉子結(jié)點深度奇偶性相同);②想要移動到任意葉子結(jié)點都需要奇數(shù)步數(shù)
對于①,玩家只要移動x個蘋果到它孩子節(jié)點上,那么這x個蘋果就一定會變成狀態(tài)②之下
對于②,玩家只要移動x個蘋果到它孩子節(jié)點上,那么這x個蘋果就一定會變成狀態(tài)①之下
而孩子結(jié)點屬于狀態(tài)①,所以當(dāng)前玩家只要移動狀態(tài)②下的x個蘋果,那么另一個玩家只要照搬你的移動,將這x個蘋果再次移動到當(dāng)前的孩子,就又變成狀態(tài)②了,若當(dāng)前已經(jīng)到葉子節(jié)點無法移動了,另一個玩家就可以直接將這x個蘋果吃掉(你就GG,這幾個蘋果就和沒有一樣!)
這樣就很明顯了,先手對于狀態(tài)②下的蘋果,無論怎么移動,最后一定都會被聰明的后手玩家用上述方法吃掉,所以狀態(tài)②的蘋果毫無意義,那么狀態(tài)①的呢,只要移動一部就會變得狀態(tài)②從而毫無意義(和沒有一樣),那這不就轉(zhuǎn)化成了裸的尼姆博弈了么?
結(jié)論:只要將所有狀態(tài)①下的蘋果數(shù)量異或,最后結(jié)果ans若為0則先手必敗,否則必勝!
那么怎么解決這道題,其實已經(jīng)好辦了,先判斷一波先手必勝還必敗。
如果已經(jīng)必敗了,那么后手作弊交換節(jié)點時就要盡量避免改變戰(zhàn)局,要知道a^b==b^a,異或是滿足交換律的,所以B可以將所以狀態(tài)①中任意兩個節(jié)點互換,或者將狀態(tài)②中任意兩個節(jié)點互換,或者將分別屬于狀態(tài)①和狀態(tài)②中但數(shù)量相同的兩堆互換,三種情況個數(shù)加在一起即是答案。
如果先手必勝,那么后手的交換一定要改變戰(zhàn)局,這個時候必須將狀態(tài)①中的某個節(jié)點和狀態(tài)②中的某個節(jié)點互換,那么怎么換呢?亦或性質(zhì)a^b^b==a,假設(shè)當(dāng)前異或結(jié)果是ans,那么只要遍歷一遍狀態(tài)①中的所有節(jié)點,對于當(dāng)前節(jié)點的蘋果個數(shù)temp,在狀態(tài)②中找到蘋果個數(shù)為ans^temp的節(jié)點,交換即可!最后統(tǒng)計一遍個數(shù)便是答案
[cpp]?view plaincopy
- //?http://codeforces.com/contest/812/problem/E??
- #include<stdio.h>??
- #include<algorithm>??
- #include<math.h>??
- #include<stdlib.h>??
- #include<map>??
- #include<vector>??
- using?namespace?std;??
- #define?LL?long?long??
- vector<LL>?G[200005];??
- map<LL,?LL>?p,?q;??
- LL?a[200005],?dep[200005],?maxdep,?jl[200005];??
- void?Sech(LL?u,?LL?p,?LL?k)??
- {??
- ????LL?i,?v;??
- ????dep[u]?=?k;??
- ????maxdep?=?max(maxdep,?k);??
- ????for(i=0;i<G[u].size();i++)??
- ????{??
- ????????v?=?G[u][i];??
- ????????if(v==p)??
- ????????????continue;??
- ????????Sech(v,?u,?k+1);??
- ????}??
- }??
- int?main(void)??
- {??
- ????LL?n,?i,?v,?ans,?sp,?sq,?temp,?lala;??
- ????scanf("%I64d",?&n);??
- ????for(i=1;i<=n;i++)??
- ????????scanf("%I64d",?&a[i]),?jl[i]?=?a[i];??
- ????sort(jl+1,?jl+n+1);??
- ????lala?=?unique(jl+1,?jl+n+1)-(jl+1);??
- ????for(i=2;i<=n;i++)??
- ????{??
- ????????scanf("%I64d",?&v);??
- ????????G[i].push_back(v);??
- ????????G[v].push_back(i);??
- ????}??
- ????maxdep?=?1;??
- ????Sech(1,?-1,?1);??
- ????ans?=?sp?=?sq?=?0;??
- ????for(i=1;i<=n;i++)??
- ????{??
- ????????if(maxdep%2==dep[i]%2)??
- ????????????p[a[i]]++,?ans?^=?a[i],?sp++;??
- ????????else??
- ????????????q[a[i]]++,?sq++;??
- ????}??
- ????if(ans==0)??
- ????{??
- ????????ans?=?sp*(sp-1)/2+sq*(sq-1)/2;??
- ????????for(i=1;i<=lala;i++)??
- ????????????ans?+=?p[jl[i]]*q[jl[i]];??
- ????????printf("%I64d\n",?ans);??
- ????}??
- ????else??
- ????{??
- ????????temp?=?ans;??
- ????????ans?=?0;??
- ????????for(i=1;i<=n;i++)??
- ????????{??
- ????????????if(maxdep%2==dep[i]%2)??
- ????????????????ans?+=?q[temp^a[i]];??
- ????????}??
- ????????printf("%I64d\n",?ans);??
- ????}??
- ????return?0;??
- }??
#include<bits/stdc++.h>//博主自己寫的垃圾代碼
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int a[maxn],dep[maxn],du[maxn],p[maxn];
map<ll,ll> cnt2;
vector<int> g;
int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=2;i<=n;i++){cin>>p[i];du[p[i]]++;}for(int i=1;i<=n;i++){if(du[i]==0)g.push_back(i);}for(int i=0;i<g.size();i++){dep[g[i]]=0;for(int j=g[i];j!=1;j=p[j]){dep[p[j]]=max(dep[j]+1,dep[p[j]]);}}ll ans=0,ans1=0,ans2=0;for(int i=1;i<=n;i++){if(dep[i]%2==0){ans=ans^a[i];ans1++;}else cnt2[a[i]]++;}ll t =0;if(ans==0){for(int i=1;i<=n;i++){if(dep[i]%2==0){t=t+cnt2[a[i]];}}ans2=n-ans1;cout<<ans1*(ans1-1)/2+ans2*(ans2-1)/2+t<<endl;}else{for(int i=1;i<=n;i++){if(dep[i]%2==0){t=t+cnt2[ans^a[i]];}} cout<<t<<endl;}
}總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博弈知识汇总
- 下一篇: ELFhash - 优秀的字符串哈希算法