bzoj1188: [HNOI2007]分裂游戏

传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1188

思路:这题比较特殊,每个豆子是一个独立的游戏,SG的下标是豆子所处的位置。

知道了这一点就很好做了。

首先对于一个位置的两个豆子,一个人走一步,另一个人也可以走这一步,所以就抵消了

从SG函数的角度理解,这两个豆子的SG值相同,最后反正会被异或掉。

所以豆子数等于a[i]%2

对于输出方案,枚举i,j,k,表示第一步由i移向j和k。

怎么判断是否合法?只要判断移动后是否为先手必败,就是移动后的局面SG值为零。

移动后的SG值只要通过原来的SG^SG[i]^SG[j]^SG[k]得到。

这一步也很好理解,i处豆子少了一个,j,k豆子多了一个,都只要异或一下就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=27;
using namespace std;
int T,n,a[maxn],sg[maxn],tot,ans;bool bo[20010];

int getsg(int x){
	if (sg[x]!=-1) return sg[x];//printf("xxxxx%d\n",x);
	memset(bo,0,sizeof(bo));
	for (int i=1;i<x;i++)
		for (int j=1;j<=i;j++)
			bo[getsg(i)^getsg(j)]=1;//,printf("%d %d\n",i,j)
	for (int i=0;;i++) if (!bo[i]) return sg[x]=i;
}

int main(){
	memset(sg,-1,sizeof(sg));
	sg[1]=0;for (int i=2;i<26;i++) sg[i]=getsg(i);
	//for (int i=1;i<=20;i++) printf("%d\n",sg[i]);
	scanf("%d",&T);
	while (T--){
		scanf("%d",&n),ans=tot=0;
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		for (int i=1;i<=n;i++) if (a[i]&1) ans^=sg[n-i+1];
		for (int i=1;i<=n;i++)
			for (int j=i+1;j<=n;j++)
				for (int k=j;k<=n;k++)
					if (!(ans^sg[n-i+1]^sg[n-j+1]^sg[n-k+1]))
						if (++tot==1) printf("%d %d %d\n",i-1,j-1,k-1);
		if (!tot) puts("-1 -1 -1");
		printf("%d\n",tot);
	}
	return 0;
}



转载于:https://www.cnblogs.com/thythy/p/5493550.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值