BZOJ1022 [SHOI2008]小约翰的游戏John(Anti-Nim游戏)



【题解】

首先,还是令SG[x]=x

结论:
先手胜有两种情况:
1. Nim和(SG[i]异或和)==0,且每堆石子数量都为1
2. Nim和!=0,且至少有一堆石子数量大于1

简单证明(YY。。。):


情况1. 每堆石子数量都为1时,堆数为偶数时先手胜,此时Nim和为0

            反之,堆数为奇数时先手必败 


情况2. 至少有一堆石子数量大于1时,

            1)若只有一堆石子数量大于1(此时Nim和!=0),先手可一定可以将局面变为奇数个1,使后手进入必败状态 

            2)若有>=2堆石子数量大于1:

               初始的Nim和==0时:

                 *1 取石子相当于减小某个数,即把某个数的某个二进制位k由1变为0,再改变低于k的位数 

                 *2 二进制位k为1的数有偶数

                 假设先手将某数a的最高第k位改为0,又改了k之后的某些位,那么后手完全可以也找到另一个二进制第k位为1的数b,

                 在第k位及之后做相同修改。若修改b之后,还存在大于1的数,就这样修改,并循环往复; 否则,后手完全可以不

                 修改b,而是转化为情况 2- 1) 的先手而取胜。此种情况后手必胜 

               初始的Nim和!=0时:先手可通过调整最大的数,将局面变为 Nim和==0,他就成为了上面情况的"后手"。此种情况先手必胜 


注意:

SG!=0不能写成SG==1!!!


【代码】

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int T,n,i,x,SG,flag;
	scanf("%d",&T);
	for(;T>0;T--)
	{
		scanf("%d",&n);
		SG=flag=0;//SG:异或和 
		for(i=1;i<=n;i++)
		{
			scanf("%d",&x);
			SG^=x;
			if(x!=1) flag=1;//flag==1:x不全为1
		}
		if( (SG==0&&flag==0) || (SG!=0&&flag==1) ) printf("John\n");
		else printf("Brother\n");
	}
	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值