Topcoder SRM637-Div1-Lv2 PathGame

涉及知识点:博弈论 SG函数

题意

\(2\) 行若干列的方格图,格子为黑色\((\#)\)或白色\((.)\),Snuke 与 Sothe 轮流在上面把白格涂黑,如果有一条从左到右的白色路径,游戏继续,否则游戏结束且最后涂色的玩家判输,保证初始有路径,双方皆用最优策略,判断最后胜者。

思路

我们记录 \(f[l][r][i]\) 为长度为 \(i\) 的全白格的 \(SG\) 函数,\(l,r\) 分别表示左右端只能从上方出发\((0)\),只能从下方出发\((1)\),上下均可出发\((2)\),列举长度为 \(1\) 时最基本的情况赋初值,枚举长度,再枚举中间的断点(涂黑的块)进行转移,显然中间涂黑块所在列 \(SG\) 函数为 \(0\),而左右两边的子块已在长度更小的情况下处理过,因此根据 \(SG\) 定理异或在一起即可。最后将原方格图根据黑格分段,求亦或和即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,f[3][3][MAXN];
string s[3];
bitset<MAXN>ava;
int main(){
    cin>>n>>s[1]>>s[2];
    n=s[1].size();
    f[0][1][1]=0;
    f[1][0][1]=0;
    f[0][0][1]=1;
    f[2][0][1]=1;
    f[2][1][1]=1;
    f[0][2][1]=1;
    f[1][2][1]=1;
    f[1][1][1]=1;
    f[2][2][1]=1;
    for(int i=2;i<=n;i++){
        for(int l=0;l<=2;l++){
            for(int r=0;r<=2;r++){
                ava.reset();
                for(int j=0;j<i;j++){
                    if(!((j==0&&l==1)||(j==i-1&&r==1))) ava[f[l][0][j]^f[0][r][i-j-1]]=1;
                    if(!((j==0&&l==0)||(j==i-1&&r==0))) ava[f[l][1][j]^f[1][r][i-j-1]]=1;
                }
                for(int j=0;j<=n;j++){
                    if(!ava[j]){
                        f[l][r][i]=j;
                        break;
                    }
                }
            }
        }
    }
    int ans=0,lasti=-1,lastdir=2;
    for(int i=0;i<n;i++){
        if(s[1][i]=='#') ans^=f[lastdir][1][i-lasti-1],lasti=i,lastdir=1;
        else if(s[2][i]=='#') ans^=f[lastdir][0][i-lasti-1],lasti=i,lastdir=0;
    }
    ans^=f[lastdir][2][n-lasti-1];
    if(ans!=0) puts("Snuke");
    else puts("Sothe");
    return 0;
}
posted @ 2024-04-24 12:55  MessageBoxA  阅读(19)  评论(0编辑  收藏  举报