[POJ2311]Cutting Game
题意
有一张\(W*H\)大小的网格纸,每个人每次可以选择一块纸片沿任意一条网格线剪开,先剪出\(1*1\)大小方格者胜。
问是否先手必胜。\(2\le W,H\le200\)
sol
首先,像这样“谁先balabala”的问题是不能直接用\(SG\)函数去做的。
考虑一下问题的转化:两者都不能把网格纸剪到有一维为\(1\)(不然对手就直接再剪一刀获胜了),不能操作者败。
这样就可以直接用\(SG\)求了。
预处理每个状态的\(SG\)值,枚举这一刀在哪里剪,可以把原问题分割成两个独立的子问题,而这个状态下的\(SG\)值就是两个子问题的\(SG\)值的\(Nim\)和(就是异或和啦)。
状态数量\(O(n^2)\),转移复杂度\(O(n)\),总复杂度\(O(n^3)\)。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 205;
int SG[N][N],b[N],W,H;
int main()
{
for (int n=2;n<=200;++n)
for (int m=2;m<=200;++m)
{
memset(b,0,sizeof(b));
for (int i=2;n-i>=2;++i) b[SG[i][m]^SG[n-i][m]]=1;
for (int i=2;m-i>=2;++i) b[SG[n][i]^SG[n][m-i]]=1;
for (int i=0;i<=200;++i) if (!b[i]) {SG[n][m]=i;break;}
}
while (scanf("%d%d",&W,&H)!=EOF) puts(SG[W][H]?"WIN":"LOSE");
return 0;
}