HDU 1850 Being a Good Boy in Spring Festival

G - Being a Good Boy in Spring Festival
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Appoint description: 

Description

一年在外 父母时刻牵挂 
春节回家 你能做几天好孩子吗 
寒假里尝试做做下面的事情吧 

陪妈妈逛一次菜场 
悄悄给爸爸买个小礼物 
主动地 强烈地 要求洗一次碗 
某一天早起 给爸妈用心地做回早餐 

如果愿意 你还可以和爸妈说 
咱们玩个小游戏吧 ACM课上学的呢~ 

下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。 
现在我们不想研究到底先手为胜还是为负,我只想问大家: 
――“先手的人如果想赢,第一步有几种选择呢?” 

Input

输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。 

Output

如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。 

Sample Input

3
5 7 9
0

Sample Output

1

nim博弈题,设s(N)=N0^N1^N2^...^Nm

1.先把所有的异或一遍(s(N)),如果是零,则先手的人输

2.题目难点是非零时如何求第一步的可行方案

思路:我们要保证赢,则要从其中一堆拿出一定量的扑克牌后,要使剩下的所有堆异或起来等于零,也就是让对方面对必输局面

我们可以把所有的扑克牌堆分为两部分,一部分B1只有一堆(也就是你要拿的那一堆,拿完之后为B1'),剩下的为另一部分B2,要使剩下的所有堆异或起来等于零,也就是s(B1’)^s(B2)==0,s(B2)易求,接下来是如何确定能不能找到这个B1’和能找到多少个B1’

两个数a,b 如果要使0~a-1中的一个数异或上b等于零,那么a肯定是大于b的,因为一个数异或上他本身才为零,并且0~a-1中只有一个数满足异或上b为零(也就是b);

所以只有当s(B1)大于s(B2)时,才有一个B1’,使s(B1’)^s(B2)==0,s(B1)也就是B1这个堆牌的数量,每个堆都遍历一遍即可求出所有的可行方案;


#include<stdio.h>
int a[200],n;
int main()
{
	int i,j,cnt=0,sum=0,cnt2;
	while(~scanf("%d",&n),n)
	{
		sum=0;
		cnt=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			cnt^=a[i];
		}
		if(cnt==0)
		printf("0\n");
		else
		{
			for(i=0;i<n;i++)
			{
				cnt2=cnt^a[i];//cnt是所有数的异或起来,在异或一遍a[i]则为除去a[i]剩下的数异或起来的结果(也就是s(B2)在网上看到,比较高效)
			//	printf("%d\n",cnt);
				if(cnt2<a[i])
				sum++;
			}
			printf("%d\n",sum);
		}
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值