【POJ 2311】Cutting Game

题目

题目链接:http://poj.org/problem?id=2311
一张 \(n\times m\) 的纸,两人轮流行动,每次行动需要在所有纸中选择一张的一行或者一列剪断,变为两张新的纸。先剪出 \(1\times 1\) 的纸的人获胜。求先手是否必胜。

思路

很明显的公平组合游戏,对于一个 \(n\times m\) 的纸,它所有候机状态为

\[\left \{ (i\times m,(n-i)\times m) | 1\leq i<n\right \}\cup \left \{ (n\times i,n\times (m-i)) | 1\leq i<m\right \} \]

由于 \(2\times 2,2\times 3,3\times 2,3\times 3\) 的纸时先手必败,所以这些纸的 \(sg\) 值全部为 \(0\)。然后递推取 \(\mathrm{mex}\) 即可。
时间复杂度 \(O(nm(n+m)+Q)\)

代码

#include <cstdio>
#include <cstring>
using namespace std;

const int N=210;
int n,m,sg[N][N];
bool vis[N];

void dfs(int n,int m)
{
	if (sg[n][m]!=-1) return;
	for (int i=2;i<n-1;i++) dfs(i,m);
	for (int i=2;i<m-1;i++) dfs(n,i);
	memset(vis,0,sizeof(vis));
	for (int i=2;i<n-1;i++) vis[sg[i][m]^sg[n-i][m]]=1;
	for (int i=2;i<m-1;i++) vis[sg[n][i]^sg[n][m-i]]=1;
	sg[n][m]=0;
	for (int i=0;vis[i];i++) sg[n][m]=i+1;
}

int main()
{
	memset(sg,-1,sizeof(sg));
	sg[2][2]=sg[2][3]=sg[3][2]=sg[3][3]=0;
	for (int i=2;i<=200;i++)
		for (int j=2;j<=200;j++)
			dfs(i,j);
	while (scanf("%d%d",&n,&m)!=EOF)
		if (sg[n][m]) printf("WIN\n");
			else printf("LOSE\n");
	return 0;
}
posted @ 2020-12-22 19:12  stoorz  阅读(98)  评论(0编辑  收藏  举报