[HNOI2007]分裂游戏

题目

这个题太妙啦

我们发现如果把一堆石子看成一个独立游戏的话显然是不可以的,因为这样的话游戏根本就不独立,于是就自闭了

我们发觉这个东西本质上还是一个\(multi\)博弈,只不过这里的单个游戏变成了每一个石子,石子在不停的分裂

我们设\(sg_x\)表示一个石子在第\(x\)堆的\(SG\)函数

如果\(x=n\),那么这个石子显然不能再移动了,于是\(sg_x=0\)

如果\(x!=n\),我们就考虑这个石子分裂产生的新位置,于是\(sg_x=mex_{i<j<=k}\{sg_{j}\bigoplus sg_k\}\)

于是我们现在在\(O(n^3)\)的时间内就可以求出\(sg\)函数的值了

之后我们再\(O(n^3)\)枚举出示状态就可以了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int sg[55],n,T,tax[100005],m;
int main() {
	T=read();m=1;
	while(T--) {
		n=read();sg[n]=0;memset(sg,0,sizeof(sg));
		for(re int i=n-1;i;--i,++m) {
			for(re int j=i+1;j<=n;j++)
				for(re int k=j;k<=n;k++) 
					tax[sg[j]^sg[k]]=m;
			while(tax[sg[i]]==m) sg[i]++;
		}
		int ans=0,tot=0;
		for(re int x,i=1;i<=n;i++)
			x=read()&1,ans^=(x*sg[i]);
		if(!ans) {puts("-1 -1 -1");puts("0");continue;}
		for(re int i=1;i<=n;i++)
			for(re int j=i+1;j<=n;j++)
				for(re int k=j;k<=n;k++) {
					ans^=sg[i];ans^=sg[j];ans^=sg[k];
					if(!ans) {
						if(!tot) printf("%d %d %d\n",i-1,j-1,k-1);
						tot++;
					}
					ans^=sg[i];ans^=sg[j];ans^=sg[k];
				}
		printf("%d\n",tot);
	}
	return 0;
}
posted @ 2019-04-23 15:05  asuldb  阅读(214)  评论(0编辑  收藏  举报