题意
有一张(W*H)大小的网格纸,每个人每次可以选择一块纸片沿任意一条网格线剪开,先剪出(1*1)大小方格者胜。
问是否先手必胜。(2le W,Hle200)
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;
}