题目:点击打开链接
第2509题也是一模一样的方法
最后一个取的人为输, 即反尼姆,在网上看了很多人写的,感觉有点晕晕乎乎的,然后大神跟我讲了一下,差不多是懂了,趁热赶紧写下来
首先必败局为T, 必胜局为S, 数字代表有几个充裕堆,充裕堆大于或等于2的时候,都写成2 。所以状态总共有T0, S0, S1, S2, T2这五种
注意T1(有一个充裕堆且局面必败)这种情况是不存在的。因为有一个充裕堆的时候局面一定是必胜的,原因是若此时孤单堆堆数为奇数,把充裕堆取完;否则,取成只剩一个。这样,就变成奇数个孤单堆,由对方取,这样你取一个孤单堆,我取一个孤单堆……最终肯定胜。
所以,由上面也可以知道,谁面对S1,谁就胜。
S2只能转换到T2,T2可以转换到S2和S1,所以局面的转化过程必然是S2->T2->S2->T2-> …… ->T2->S1->S0->T0->……->S0->T0(全0)
贴上两个代码,我觉得第一个代码更直观,更能体现思想。
#include <stdio.h>
int main (void)
{
int n;
while(scanf("%d", &n) != EOF)
{
int a, count = 0, sum = 0;
int i;
for(i = 0; i < n; i++)
{
scanf("%d", &a);
sum ^= a;
if(a > 1)
count++;
}
if(count == 1)//充裕堆等于1必胜
printf("Yes\n");
else if(count >= 2 && sum != 0)//充裕堆大于2且异或和不为0必胜
printf("Yes\n");
else if(count == 0 && sum == 0)//充裕堆为0且是偶数堆必胜
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
还可以总结一下结论就是: 先手胜当且仅当①所有堆石子数都为1且异或和为0(即有偶数个孤单堆);②存在某堆石子数大于1且异或和不为0. 下面的代码就是直接根据结论写的。
#include <stdio.h>
int main (void)
{
int n, t;
scanf("%d", &t);
while(t --)
{
scanf("%d", &n);
int a, f = 0, sum = 0;
int i;
for(i = 0; i < n; i++)
{
scanf("%d", &a);
sum ^= a;
if(a > 1)
f = 1;
}
if(f)
{
if(sum == 0)
printf("Brother\n");
else
printf("John\n");
}
else
{
if(sum == 0)
printf("John\n");
else
printf("Brother\n");
}
}
return 0;
}