介绍:
有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
正解
每堆物品的数量进行异或运算 结果等于0 就是奇异局势 就是必败态
原理
我们用(a,b,c)表示某种局势,首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情形。
这些局势都满足 a^ b ^c=0
而异或运算法则是 相同为0 不同为1 根据运算法则 面对奇异局你不论怎么拿 都不会还=0(满足性质2)
而不满足的a^ b ^c=0的局势 我们都可以使其变成a^ b^c=0
因为 局面(a,b,c) 我们只要令最大的数 比如是a 令a=b+c 就变成了 (b+c)^ b^ c=(b^ b)+(c^c)=0(满足性质1)
所以 a^b ^c=0就是i我们要找的奇异局势 必败状态
————————————————————————————————————
类型一:先手的人想赢,第一步有多少种选择呢?
#include<stdio.h>
#include<math.h>
int a[105];
int main()
{
int i,j,k;
int n;
while(~scanf("%d",&n))
{
if(n == 0)
break;
int ans = 0;
int count = 0;
for(i = 0;i < n;i++)
{
scanf("%d",&a[i]);
ans = ans ^ a[i];
}
int s;
for(i = 0;i < n;i++)
{
s = ans ^ a[i];
if(s < a[i])
count++;
}
printf("%d\n",count);
}
return 0;
}
这里我想说的是:我们可以先跳过某个数a[i],先对除其之外的所有数求XOR和,如果这个 XOR和<a[i] 那么说明有戏啦!我只需要抽走a[i]-XOR个数字,那么对方面临的就是奇异局势必败态了。
类型二:先取完的人是winner(先取完者判胜)。
这个时候直接求Nim和,若Nim和是0,那么先手面临奇异局势,则winner是后手;反之是先手
类型三:反尼姆博弈(先取完者判输)
反尼姆博弈结论:n堆物品,全部异或结果为ans,统计富裕堆的个数为c;
先手胜有两种情况:
1:各堆石子数目异或结果不等于0,且存在有石子数目大于1的石子堆。
2:各堆石子数目异或结果等于0,且所有石子堆数目全部为1。(即所有堆都为1,且堆的数量为偶数)
借用国家集训队贾志豪的论文才看懂(太菜了…)hiahiahia
#include<cstdio>
int main()
{
int t,m,n;
scanf("%d",&t);
while(t--)
{
int ans=0,c=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&m);
if(m>1) c++;//统计富裕堆个数
ans^=m;
}
if((!ans && c<2) || (ans && c)) printf("先手胜\n");
else printf("后手胜\n");
}
return 0;
}