Codeforces 168D Wizards and Huge Prize

传送门:http://codeforces.com/problemset/problem/168/d

思路:这题比较恶心,细节很多,不过还好cf可以看数据...

首先考虑一个弱化版,只会横着或竖着以及横着和竖着一起来。

我们可以发现,一次操作后就相当于把一个大的游戏分成1或2或4个独立小游戏

SG值与位置也有关系,所以SG[u][d][l][r]表示左上坐标为(u,d)右下坐标为(l,r)的SG值

然后对于斜着的,我们考虑把它旋转45度,但是这有一个问题,一次操作并不能分出几个独立的小游戏(画图就可以发现了)

于是考虑把棋盘黑白染色,这样就可以分出独立的游戏了。


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int sg[25][25][25][25],b[25][25],n,N,M;char a[25][25];bool bo[1010];

int work(int u,int d,int l,int r){
	if (u>d||l>r) return 0;
	if (sg[u][d][l][r]!=-1) return sg[u][d][l][r];	
	for (int i=u;i<=d;i++)
		for (int j=l;j<=r;j++)
			if (b[i][j]==1) work(u,i-1,l,r),work(i+1,d,l,r);
			else if (b[i][j]==2) work(u,d,l,j-1),work(u,d,j+1,r);
			else if (b[i][j]==3) work(u,i-1,l,j-1),work(u,i-1,j+1,r),work(i+1,d,l,j-1),work(i+1,d,j+1,r);
	memset(bo,0,sizeof(bo));
	for (int i=u;i<=d;i++)
		for (int j=l;j<=r;j++)
			if (b[i][j]==1) bo[work(u,i-1,l,r)^work(i+1,d,l,r)]=1;
			else if (b[i][j]==2) bo[work(u,d,l,j-1)^work(u,d,j+1,r)]=1;
			else if (b[i][j]==3) bo[work(u,i-1,l,j-1)^work(u,i-1,j+1,r)^work(i+1,d,l,j-1)^work(i+1,d,j+1,r)]=1;
	for (int i=0;;i++) if (!bo[i]) return sg[u][d][l][r]=i;
}

int getans(int odd){
	memset(sg,-1,sizeof(sg));
	memset(b,0,sizeof(b));
	for (int i=1;i<=N;i++)
		for (int j=1;j<=M;j++)
			if (((i+j)&1)==odd)
				b[(i+j)>>1][(j-i+N+1)>>1]=a[i][j]=='L'?1:a[i][j]=='R'?2:3;
	/*for (int i=1;i<=n;i++,puts(""))
		for (int j=1;j<=n;j++)
			printf("%c",b[i][j]==1?'L':b[i][j]==2?'R':b[i][j]==3?'X':'0');
	puts("");*/ 
	return work(1,n,1,n);
}

int main(){
	while (scanf("%d%d",&N,&M)!=EOF){
		n=(N+M)>>1;
		for (int i=1;i<=N;i++) scanf("%s",a[i]+1);
		puts(getans(0)^getans(1)?"WIN":"LOSE");
	}
	return 0;
}


posted @ 2015-08-06 17:48  orzpps  阅读(118)  评论(0编辑  收藏  举报