分析:
首先假设先手的人有必赢策略。
问题则转化为=>在任意一堆拿任意K张牌,并且所有堆的nim-sum=0(P-position)的方案总数。
现在我们先看一个例子(5,7,9),并假设从第一堆取任意K张牌。
排除第一堆牌的nim-sum为 7^9=14
0111
^1001
-------
1110
如果要使所有堆的nim-sum=0成立,则第一堆取掉K张以后必定为1110,因为X^X=0。
所以要观察 5-k=14 k>0 成立,此例子(在第一堆取任意K张牌)明显的不成立。但并不代表在第二或第三堆取任意K张牌的解不成立。
现在看第二个例子(15,7,9),并假设从第一堆取任意K张牌。
排队第一堆牌的nim-sum为7^9=14,和第一个例子相同,所以问题变为观察 15-k=14 k>0 是否成立。
当然这个例子是成立的。
总结得出:
在任意一堆拿任意K张牌,并且所有堆的nim-sum=0 成立的条件为:排除取掉K张牌的那一堆的nim-sum必须少于该堆牌上的数量(例子二),否则不能在此堆上取任意K张牌使所有堆的nim-sum=0成立(例子一)。
故总方案数为 (在任意一堆拿任意K张牌,并且所有堆的nim-sum=0 成立) 的总数。
现在分析先手的人没有必赢策略。
因为没有必赢策略,所以a1^a2^a3^...^an=0(nim-sum=0),一定不存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。因为异或运算满足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以将ai改变成ai'不是一个合法的移动。
分析完之后看代码容易明白了,PS:代码不是我的,是参考别人代码得出上述分析的。
附上 Thomas S.Ferguson 的PDF: Game Theory
#include <iostream>
using namespace std;
int main()
{
int m,n,k,j,i,t;
int a[102];
while (scanf("%d",&n)!=EOF,n)
{
int ans = 0;
for (i=0;i<n;i++)
{
scanf("%d",&a[i]);
ans = ans^a[i];
}
//-----------------------------------
int counter= 0;
for (i=0;i<n;i++)
{
if (i == 0)
{
ans = ans^a[i];
}
else
{
ans = ans^a[i-1];
ans = ans^a[i];
}
if (ans < a[i])
{
counter++;
}
}
printf("%d\n",counter);
}
return 0;
}