非常玄妙的博弈入门
好神仙的题啊
其实这就是经典的(Nim)问题
如果所有石子的异或和为(0),那么这就是一个必败状态
这个我只会感性理解一下
首先所有的石子都是(0),异或和肯定是(0),这也自然是一个必败状态
而如果异或和不是(0),我们设异或和为(X)
我们可以找到这个(X)的最高位,显然那些石子堆里至少有一个这一位上也是(1)的,设这一个石子堆是(x_i)
那么就有
[x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n=X
]
那么显然
[x_1⊕x_2⊕x_3⊕...⊕x_i⊕...x_n⊕X=0
]
根据异或的结合律
[x_1⊕x_2⊕...⊕(x_i⊕X)⊕...x_n=0
]
也就是说原来的(x_i)变成(x_i⊕X)就好了,也就是要取走(x_i-x_i⊕X),这样就可以使得下一步变成必败状态
由于我们取走的一定得是正数,所以得满足(x_i-x_i⊕X>0)
但是如果(X=0)的话,(x_i⊕X=x_i),所以(x_i-x_i⊕X=0),取走的是(0),并不满足游戏规则
所以一大波分析下来突然就觉得好有道理
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 500005
#define lowbit(x) ((x)&(-x))
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
int n,a[maxn];
int ans,t;
int main()
{
n=read();
for(re int i=1;i<=n;i++) a[i]=read(),ans^=a[i];
t=ans;
if(!ans)
{
puts("lose");
return 0;
}
for(re int i=1;i<=n;i++)
{
if(a[i]-(a[i]^ans)>0)
{
printf("%d %d",a[i]-(a[i]^t),i);
putchar(10);
a[i]=(a[i]^t);
break;
}
}
for(re int i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}