版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/82977541
题目链接:hdu 4388
参考博客:https://blog.csdn.net/y1196645376/article/details/52143551
题意:
最初有n堆石子,每堆石子个数已知。两人轮流执行操作,如果当某人无法执行有效操作时即输。
操作分两步:
第一步为:选择其中一堆石子假定石子个数为a,拿走个数不为0的一些石子使得该堆石子剩余k个并且保证(0 < k < a,k^a < a),^为异或符号。
第二步为:加入一堆新的石子,石子个数为k^a,当然你也可以使用技能使得加入的石子个数变为(2k)^a。不过每个人每局游戏只能使用一次技能。
无法执行有效操作即第一步或者第二步无法执行时。
题解:直接看代码,里面有很详细的注释。
///先看下题目要求,每次留下的k,满足 0<k<n && kXORn <n,
///这说明,k只能在n中取二进制位1的数位,例如n=5(101),那么k只能是4(100)或者1(001)
///还能知道堆数为2^i时(二进制只有一位1),不能再分了,已到达边界了。
///然后我们假设先考虑一堆石子(n=1),k为这堆石子二进制位为1的个数,假设为偶数,先手win,也就是n+k为奇数时,先手win
///接着我们考虑有多堆石子(n>1),sum为这堆石子二进制1的个数,类比于一堆石子,sum+n为奇数时先手win,多堆可以看做单堆单堆的取,
///对了,每位选手还有一次技能加成的机会,我们要清楚的一点的是,这次加成的是用在新加堆上的,并且也不会改变新加堆的二进制位为1的个数
///例如n=13(1101),留k=5(101),2*k=1010, k XOR n=1000 ,2*k XOR n=0111,可见,不管用不用技能,新加堆的二进制位为1的个数的奇偶数还是没变。over。
/*
例如
n=15(1111)
1 111 先手
1 100 11 后手
1 100 1 1 先手
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int main()
{
int ncase;
scanf("%d",&ncase);
for(int T=1;T<=ncase;T++)
{
int n;
scanf("%d",&n);
int x,sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
sum+=__builtin_popcount(x); ///库函数查找x数字二进制为1的个数,
///这库函数有个小坑,前面的下横线要两条,艹。
}
if((sum+n)&1) printf("Case %d: Yes\n",T);
else printf("Case %d: No\n",T);
}
return 0;
}