【博弈】取石子游戏(P2599)
正題
P2599
題目大意
給n堆石子,第 i 堆有 aia_iai? 個石子,每次可以從最左邊或者最右邊的一堆里面取若干個,兩個人輪流取,問先手是否存在必勝策略
解題思路
設 li,jl_{i,j}li,j? 為在 [i,j][i,j][i,j] 右邊添加一堆大小 li,jl_{i,j}li,j? 的石子,會使得先手必敗,ri,jr_{i,j}ri,j?同理
首先證明 li,jl_{i,j}li,j? 只存在一個
如果存在兩個 li,jl_{i,j}li,j?,那么先手顯然可以從大的直接操作為小的,那么先手必勝,不滿足先手必敗,所以最多有一個 li,jl_{i,j}li,j?
接下來證明一定存在 li,jl_{i,j}li,j?
如果不存在 li,jl_{i,j}li,j?,那么左邊無論加多少個數都是必勝狀態
如果先手選左邊那么必定到必勝狀態,不滿足先手必勝,所以先手肯定選右邊
選了若干數后,一定滿足無論左邊加的是多少都必敗,那么后手在左邊選一個數則又回到了必敗狀態,不滿足先手必勝
綜上,必定存在 li,jl_{i,j}li,j?
同理必定存在 ri,jr_{i,j}ri,j? 且只存在一個
接下來考慮如何轉移
對于 li,jl_{i,j}li,j? 的求解,考慮從 [i,j?1][i,j-1][i,j?1] 轉移,那么必定和 li,j?1,ri,j?1l_{i,j-1},r_{i,j-1}li,j?1?,ri,j?1? 有關,令 L=li,j?1,R=ri,j?1L=l_{i,j-1},R=r_{i,j-1}L=li,j?1?,R=ri,j?1?
如果先手左邊拿到 L,那么右邊直接取空則先手必敗(右邊同理)
如果先手左邊拿完,那么對于后手就是必勝得狀態
否則先手左邊拿多少必勝決策,右邊拿同樣多即可
最后判斷 a1a_1a1? 是否等于 l2,nl_{2,n}l2,n? 即可
時間復雜度 O(n2T)O(n^2T)O(n2T)
code
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 1010 using namespace std; int T,n,a[N],l[N][N],r[N][N]; int main() {scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%d",&a[i]);l[i][i]=r[i][i]=a[i];}for(int len=2;len<n;++len)for(int i=1;i<=n-len+1;++i){int j=i+len-1,L,R;L=l[i][j-1];R=r[i][j-1];if(a[j]==R)l[i][j]=0;else if(L<=a[j]&&a[j]<R)l[i][j]=a[j]+1;else if(a[j]<L&&a[j]<R)l[i][j]=a[j];else if(L<a[j])l[i][j]=a[j];else l[i][j]=a[j]-1;L=l[i+1][j];R=r[i+1][j];if(a[i]==L)r[i][j]=0;else if(R<=a[i]&&a[i]<L)r[i][j]=a[i]+1;else if(a[i]<R&&a[i]<L)r[i][j]=a[i];else if(R<a[i])r[i][j]=a[i];else r[i][j]=a[i]-1;}if(l[2][n]!=a[1])puts("1");else puts("0");}return 0; }總結
以上是生活随笔為你收集整理的【博弈】取石子游戏(P2599)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【图论】旅行者(P5304)
- 下一篇: 各种有用的东西留言板