对于n堆石子,某个人没有石子可取为输,接下来的必胜态和必败态是对于第一个人来说的.
首先是必胜态和必败态,如果不管第一个怎么取都不能胜,那么为必败态,否则为必胜态.
如果对于n堆石子数取异或值为0,则为必败态,反之为必胜态.
for (int i = 0; i < n; i ++)
{
scanf("%lld", &a[i]);
ans ^= a[i];
}
如果第一个人为必胜态,那么一定可以取一定的石子使第二个人取的石子为必败态.证明如下:
ans(不为0)的最高位一定为1(设为k),那么在a[n]中一定存在一个数在第k位上也为1,那么这意味着我在这一位上减少a[i]-(a[i]^ans)(a[i]一定大于a[i]^ans,即这样减一定是合理的)就能使这一位的第k位变为0,这时第i位就变成了a[i]^ans,它与其余每堆的数量异或一定为0,即为必败态.
综合代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 500010
typedef unsigned long long ULL;
ULL a[N];
int main()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 0; i < n; i ++)
{
scanf("%lld", &a[i]);
ans ^= a[i];
}
if (ans == 0)
{
printf("lose");
return 0;
}
int k = 0, b = ans;
while (b)//求ans的最高位,同时最好不要修改ans.
{
b >>= 1;
k++;
}
// printf("%d %d\n", k, 10^ans);
for (int i = 0; i < n; i ++)
{
if((a[i] >> k - 1) & 1)
{
int b = a[i] - (a[i] ^ ans);//一定要加上括号,我就没加括号wa了几次.
printf("%d %d\n", b, i + 1);//输出修改的个数和修改的堆数.
a[i] = a[i] ^ ans;
break;
}
}
for (int i = 0; i < n; i ++)
printf("%d ", a[i]);//输出修改后的每堆的个数.
return 0;
}
这是一个最简单的nim游戏,没有太大的变化.
博主是新手,望各位大佬将问题本人的问题提出来,谢谢各位!