把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【博弈论】游戏-纪中集训




考场上面就过了,但还是想说一下。
一看到Alice和Bob玩游戏就知道是博弈
刚开始还是想暴力
但是关于博弈的知识只记得是Nim游戏可以用异或和,还有就是sg函数。
看了一下异或和应该不可做,所以就开始算sg。
每个状态的子状态都只有2个:删去最后一行,或者是最后一列
要判断每一行,每一列的和是否是偶数,用前缀和处理
(这里据说可以用异或运算,但是我还没有搞出来,还据说可以压成一维的空间,也没有搞出来)
我感觉自己用的是假的sg函数,但sg函数的具体值好像没什么意义 用0表示必败态,用1表示非必败态(必胜态)
如果当前状态可以转移到必败态,那它就是必胜态,否则就是必败态。

刚开始写得很乱,后来整合了一下,压到了一个双重循环里面。想思路的时候,还是分开想比较好,码的时候,整合一下要清爽一些,(或许会)快一些。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 1005
#define INF 0x3f3f3f3f
int a,s1[MAXN][MAXN],s2[MAXN][MAXN],sg[MAXN][MAXN];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,ans;
		scanf("%d",&n);
		sg[0][0]=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&a);
				a%=2;
				s1[i][j]=(s1[i][j-1]+a)%2;
				s2[i][j]=(s2[i-1][j]+a)%2;
				sg[i][j]=0;
				if(s1[i][j]==0)
				{
					if(sg[i-1][j]==0)
						sg[i][j]=1;
				} 
				if(s2[i][j]==0) 
				{
					if(sg[i][j-1]==0)
						sg[i][j]=1;
				}
			}
		if(sg[n][n]==0) printf("L\n");
		else printf("W\n");
	}
	return 0;
}

嗯,我把异或弄出来了!
其实比较简单吧
因为:
1 ⊕ 1 = 0 1⊕1=0 11=0
1 ⊕ 0 = 1 1⊕0=1 10=1
0 ⊕ 1 = 1 0⊕1=1 01=1
0 ⊕ 0 = 0 0⊕0=0 00=0
恰好对应模2的余数运算
所以:

s1[i][j]=(s1[i][j-1]+a)%2;
s2[i][j]=(s2[i-1][j]+a)%2;

s1[i][j]=s1[i][j-1]^a;
s2[i][j]=s2[i-1][j]^a;

快了100多ms 还行


(其实我感觉压了空间也没什么用啊 1000的数据 我就3个二维数组 能过就行

我还以为是什么多高级的操作 ,原来就是把i-1那里抹掉不算,毕竟在算出sg函数之后本身的前缀和数组没有任何用处(而且这个前缀和数组只需要反应和的奇偶性)
s1表示第i行的前缀和,s2表示第j行的前缀和
于是:

s1[i][j]=s1[i][j-1]^a;
s2[i][j]=s2[i-1][j]^a;

s1[i]=s1[i]^a;
s2[j]=s2[j]^a;

嗯?我WA了?原来是没有清0 (最短路逃

for(int i=1;i<=n;i++)
			s1[i]=s2[i]=0;

memset要谨慎使用

嗯?怎么又快了200多ms? 687ms->481ms

posted @ 2019-08-01 20:42  Starlight_Glimmer  阅读(12)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end