sg函数的本质就是把游戏转化成nim博弈,其他就很简单了。。直接看论文就好了
王的论文里提到的take&break问题在挑战上有,此题其实也就是一个take&break问题,i位置上的石头的数目是(n-1-i)然后可以变成(n-1-j)和(n-1-k)求这两个局面的异或然后就可以搞sg了其他很简单的吧。。。
关键是把张一飞的论文搞懂就明白了,那是这题的理论基础。2002年 张一飞:透析一类搏弈游戏的解答过程,acdream群里也有论文
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, s[200], sg[100];
bool temp[100000];
int stackk[100000], top = -1;
void init()
{
for (int i = 0; i <= 23; i++)
{
for (int j = 0; j < i; j++)
for (int k = j; k < i; k++)
{
temp[sg[j] ^ sg[k]] = 1;
}
int q = 0;
while (temp[q])q++;
sg[i] = q;
for (int i = 0; i < 1000; i++)
temp[i] = 0;
}
}
int main()
{
int t;
int k = 1;
init();
while (scanf("%d", &n)&&n)
{
int ans = 0;
for (int i = 0; i < n; i++)
{
scanf("%d", &s[i]);
if (s[i] & 1)
ans ^= sg[n - 1 - i];
}
if (ans == 0)
{
printf("Game %d: -1 -1 -1\n", k++);
}
else
{
int ans1 = -1, ans2 = -1, ans3 = -1;
for (int i = 0; i < n; i++)
{
if (s[i] == 0)continue;
if (ans1 != -1)break;
for (int j = i + 1; j < n; j++)
{
if (ans1 != -1)break;
for (int k = j; k < n; k++)
{
if (ans1 != -1)break;
if ((ans^sg[n - 1 - i] ^ sg[n - 1 - j] ^ sg[n - 1 - k])==0)
ans1 = i, ans2 = j, ans3 = k;
}
}
}
printf("Game %d: %d %d %d\n", k++, ans1, ans2, ans3);
}
}
return 0;
}