[bzoj1022] [SHOI2008]小約翰的遊戲John
阿新 • • 發佈:2019-02-08
int 我們 sam 有趣 fin amp desc 單詞 sample
Description
小約翰經常和他的哥哥玩一個非常有趣的遊戲:桌子上有n堆石子,小約翰和他的哥哥輪流取石子,每個人取的時候,可以隨意選擇一堆石子,在這堆石子中取走任意多的石子,但不能一粒石子也不取,我們規定取到最後一粒石子的人算輸。小約翰相當固執,他堅持認為先取的人有很大的優勢,所以他總是先取石子,而他的哥哥就聰明多了,他從來沒有在遊戲中犯過錯誤。小約翰一怒之前請你來做他的參謀。自然,你應該先寫一個程序,預測一下誰將獲得遊戲的勝利。
Input
本題的輸入由多組數據組成第一行包括一個整數T,表示輸入總共有T組數據(T≤500)。每組數據的第一行包括一個整數N(N≤50),表示共有N堆石子,接下來有N個不超過5000的整數,分別表示每堆石子的數目。
Output
每組數據的輸出占一行,每行輸出一個單詞。如果約翰能贏得比賽,則輸出“John”,否則輸出“Brother”,請註意單詞的大小寫。
Sample Input
2
3
3 5 1
1
1
Sample Output
John
Brother
Solution
這玩意好像叫\(\rm Anti-Nim\)?
先說結論,先手必勝的條件是:
- \(SG=0\)且每堆石子數量都為\(1\)。
- 或者\(SG\ne 0\)且有任意一堆石子數量大於\(1\)。
其中,\(SG\)為石子數的異或和。
對於第一種情況,異或和為\(0\)就是說有偶數堆石子,顯然先手必勝,否則先手必敗。
對於第二種情況,再分情況討論下:
- 有且僅有一堆石子數量大於\(1\),那麽,先手必然有辦法把局面轉換成上一種情況。
- 有兩堆及以上的石子數量大於\(1\),那麽先手必然可以把局面轉換成\(SG=0\)的情況,然後若當前只有兩堆大於\(1\)的,且後手使之變成了一堆大於\(1\)的情況,那麽先手必勝,否則後手必然會破壞\(SG=0\)的局面,然後循環往復,一定會轉換成前一種情況,此時先手必勝。
一句話代碼:
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } #define write(x) printf("%d\n",x) const int maxn = 2e5+10; void solve() { int n,bo=0,s=0;read(n); for(int i=1,x;i<=n;i++) read(x),s^=x,bo|=(x>1); if((!bo&&!s)||(s&&bo)) puts("John"); else puts("Brother"); } int main() { int T;read(T);while(T--) solve(); return 0; }
[bzoj1022] [SHOI2008]小約翰的遊戲John