【bzoj3895】【取石子】【博弈論+記憶化搜尋】
阿新 • • 發佈:2019-01-27
Description
Alice和Bob兩個好朋含友又開始玩取石子了。遊戲開始時,有N堆石子 排成一排,然後他們輪流操作(Alice先手),每次操作時從下面的規則中任選一個: ·從某堆石子中取走一個 ·合併任意兩堆石子 不能操作的人輸。Alice想知道,她是否能有必勝策略。Input
第一行輸入T,表示資料組數。 對於每組測試資料,第一行讀入N。 接下來N個正整數a1,a2…an,表示每堆石子的數量。Output
對於每組測試資料,輸出一行。 輸出YES表示Alice有必勝策略,輸出NO表示Alice沒有必勝策略。Sample Input
23
1 1 2
2
3 4
3
2 3 5
Sample Output
YESNO
NO
HINT
100%的資料滿足T<=100, N<=50. ai<=1000 題解:考慮如果不存在石子數為1的堆。 設這種狀態下運算元為x,顯然x等於石子總數加運算元減1。 可以證明當x為奇數時先手必勝。當x為偶數時先手必敗。 如果只有1堆石子,該結論顯然成立。 如果有多堆石子,每堆石子個數都大於1,並且x為偶數,下面我們證明這樣先手必敗。 1.如果先手選擇合併兩堆石子,那麼每堆石子的個數依然大於1,x變為奇數。 2.如果先手選擇從一堆石子數大於2的堆中拿走一枚石子,那麼同上每堆石子個數依然大於1,x變為奇數。#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,f[55][50055],T,x,a,b,vis[55][50055]; int dfs(int a,int b){ if (a==0) return b&1; if (b==1) return dfs(a+1,0); if (vis[a][b]) return f[a][b];vis[a][b]=1; if (a&&!dfs(a-1,b)) return f[a][b]=1; if (a&&b&&!dfs(a-1,b+1)) return f[a][b]=1; if (a>=2&&!dfs(a-2,b+2+(b?1:0))) return f[a][b]=1; if (b&&!dfs(a,b-1)) return f[a][b]=1; return f[a][b]=0; } int main(){ scanf("%d",&T); while (T--){ scanf("%d",&n);a=0;b=-1; for (int i=1;i<=n;i++){ scanf("%d",&x); if (x==1) a++; else b+=x+1; } if (b==-1) b=0; if (dfs(a,b)==1) printf("YES\n"); else printf("NO\n"); } }