3c++
3spa
1 1 2code
2blog
3 4ip
3input
2 3 5it
YESio
NOclass
NOim
我天,真神仙題!
這題實際上是博弈論DP,一開始還想着直接用SG * 過去。
咱們先從最簡單的入手:
只有一堆石子時咱們能夠不考慮合併形成的影響那麼一我的贏的狀況只有多是他剩下能夠進行的操做數是奇數。
(這裏咱們發現剩下能夠進行的操做數只有取一個石子)
那若是有兩個堆。
(假設只有一個石子的堆叫作寂寞堆,大於一個石子的堆叫作熱鬧堆)
那麼咱們要分兩種狀況分別討論:
\(1.\) 咱們有兩個堆,一個寂寞堆一個熱鬧堆。
那麼咱們假設寂寞堆 \(1\) 個石子,熱鬧堆 \(2\) 個石子,那麼很明顯咱們當前只有要麼從兩個堆裏取一個,要麼合併。
首先考慮合併:合併以後熱鬧堆的奇偶性變了,同時合併以後取的是對手,這樣就保證了對手贏。
考慮先把寂寞堆取完,那麼咱們在熱鬧堆中是能夠直接根據奇偶求出誰會贏。若是先取熱鬧堆對手是有贏的策略的。
到這裏咱們發現好像寂寞堆會影響答案,若是隻有熱鬧堆,熱鬧堆之間的合併不會改變他們的奇偶,對咱們考慮沒有影響,只會致使贏輸的人不同。
但若是出現了寂寞堆,寂寞堆的合併會影響熱鬧堆的奇偶性,因此要特殊考慮寂寞堆。
這個時候就要咱們上博弈論DP了 然而我不知道爲何要上(逃
設狀態 \(f[i][j]\) 表示有 \(i\) 個寂寞堆,\(j\) 次對於熱鬧堆的操做時當前操做的人是贏仍是輸。
這個狀態好詭異
咱們轉移怎麼辦呢?
分類討論一下:
\(1.\) 寂寞堆操做
\(2.\) 熱鬧堆操做
這樣以後好像就沒啥子了。注意一下細節就莫得了。
#include<bits/stdc++.h> using namespace std; int T,n; const int N=55,M=1005; int a[N],f[N][M*N]; inline int dfs(int num,int sum){ if(num<=0 && sum<=0) return 0; if(f[num][sum]!=-1) return f[num][sum]; if(num<=0) return f[num][sum]=(sum&1); if(sum==1) return f[num][sum]=dfs(num+1,0); f[num][sum]=0; if(num && !dfs(num-1,sum)) return f[num][sum]=1; // 拿一個寂寞堆的石子 if(sum && !dfs(num,sum-1)) return f[num][sum]=1; // 把一個熱鬧堆裏拿掉一個石子 if(num && sum && !dfs(num-1,sum+1)) return f[num][sum]=1; // 把一個寂寞堆合併到熱鬧堆上 if(num>1 && !dfs(num-2,sum+2+(sum?1:0))) return f[num][sum]=1; // 把兩個寂寞堆合併 return f[num][sum]; } int main(){ scanf("%d",&T); memset(f,-1,sizeof(f)); while(T--){ int cnt=0,step=0; scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); if(a[i]==1) cnt++; if(a[i]>1) step+=a[i]+1; } if(step) step--; printf("%s\n",dfs(cnt,step)?"YES":"NO"); } return 0; }