问题:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此时没有任何合法的移动)。
要知道,像Nim游戏这种博弈问题,最重要的是寻找必败态。这个必败态的意思就是,这样一种局面摆在面前的话先手必败。其严格定义如下:1、无法进行任何移动的局面是必败态;2、可以移动到必败态的局面是非必败态;3、在必败态做的所有操作的结果都是非必败态。通俗来讲就是自己处在非必败态上总能移动到必败态把必败态留给对方,而对方处在必败态的话总只能移动到非必败态,把非必败态留给自己。对于NIM游戏,局面是必败态当且仅当所有堆硬币的数量都异或起来结果为0,即:
a1^ a2…^an = 0
为了证明之,我们只要证明它满足上面必败态三条性质即可。
第一个命题显然,最终局面只有一个,就是全0,异或仍然是0;
第二个命题,对于局面(a1,a2,…,an),如果a1^ a2…an不为0,一定存在某个合法的移动,将ai改变成ai’后满足a1 ^ a2…ai…an = 0。不妨设a1 ^ a2 ^… ^an =k,则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时ai ^ k<ai一定成立。则我们可以将ai改变成ai’ = ai ^ k,此时 a1 ^ a2 ^… ^ai ^… ^an = a1 ^ a2 ^ … ^an ^k = 0;
第三个命题,对于某个局面(a1,a2,…,an),若 a1 ^ a2 ^ … ^an = 0,一定不存在某个合法移动,将ai改变成ai’后满足 a1 ^ a2 ^… ^ ai’ ^… ^an = 0。因为异或运算满足消去律,由a1 ^ a2 ^ … ^an = a1 ^ a2 ^ … ^ai’ ^ … ^ an可以得到 ai = ai’。所以将ai改变成ai’不是一个合法的移动。证毕。
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
int n,ans=0,a;
cin>>n;//可以用scanf
for(int i=0;i<n;i++){
cin>>a;//可以用scanf
ans^=a;
}
if(ans==0) printf("B");
else printf("A");
}