BZOJ 1022 Luogu P4279 [SHOI2008]小约翰的游戏 (博弈论)
題目鏈接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=1022
(luogu) https://www.luogu.org/problemnew/show/P4279
題解:
大力出奇跡系列。。
我找了一小時規律,瞎猜了一個結論,看著都不靠譜,結果它居然過了。。。。
結論: 若所有\(a_i\)都等于\(1\), 則后手必勝當且僅當\(n\)是奇數;否則后手必勝當且僅當所有\(a_i\)異或和為\(0\).
既然對了那就口胡一個證明:
(1) 當所有\(a_i\)都為\(1\)時,后手必勝當且僅當\(n\)是奇數,顯然。
(2) 否則,如果大于\(1\)的數恰好有\(1\)個,那么如果\(n\)是奇數,則把大于\(1\)這一堆拿成\(1\), 否則把大于\(1\)這一堆拿成\(0\)即可,因此先手必勝。
(3) 如果大于\(1\)的數多于\(1\)個呢?我們發現第(2)種情況的結論符合Nim游戲的一般結論(后手必勝當且僅當異或和為\(0\)),而對于任何一個大于\(1\)的數恰好有\(1\)個的狀態,不可能一步變成所有數都等于\(1\), 因此情況(1)不會影響到情況(3)。故大于\(1\)的數多于一個時,依然符合Nim游戲的一般結論。
記住,博弈論千萬不要死抓著SG函數不放!勝負分析才是最本質的,另外有時候需要轉化模型(如AGC002E).
代碼
#include<cstdio> #include<cstdlib> #include<cstring> #include<cassert> #include<iostream> using namespace std;inline int read() {int x=0; bool f=1; char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=0;for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');if(f) return x;return -x; }int n;int main() {int T; scanf("%d",&T);while(T--){int n; scanf("%d",&n);int x=0,c=0;for(int i=1; i<=n; i++) {int a; scanf("%d",&a); x^=a; c+=(a==1)?1:0;}if(c==n){if(n&1) printf("Brother\n"); else printf("John\n");}else{if(x==0) printf("Brother\n"); else printf("John\n");}}return 0; }總結
以上是生活随笔為你收集整理的BZOJ 1022 Luogu P4279 [SHOI2008]小约翰的游戏 (博弈论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 2281 Luogu P249
- 下一篇: UOJ #395 BZOJ 5417 L