题目链接:uva 1378 - A Funny Stone Game
题目大意;两个人玩游戏,对于一个序列,轮流操作。每次选中序列中的i,j,k三个位置要求i<j≤k,然后arr[i]减1,对应的arr[j]和arr[k]加1,不能操作的人输,问先手是否必胜。必胜的话给出字典序最下的必胜方案。负责输出-1.
解题思路:首先预处理出各个位置上的SG值,然后对于给定序列,枚举位置转移状态后推断是否为必败态就可以。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30;
int n, g[maxn], s[maxn];
int SG (int l) {
int vis[1000];
memset(vis, 0, sizeof(vis));
for (int i = 0; i < l; i++) {
for (int j = 0; j < l; j++)
vis[g[i]^g[j]] = 1;
}
int ret = -1;
while (vis[++ret]);
return ret;
}
void init () {
g[0] = 0;
for (int i = 1; i < maxn; i++)
g[i] = SG(i);
}
int judge () {
int ret = 0;
for (int i = 0; i < n-1; i++) {
if (s[i]&1)
ret ^= g[n-1-i];
}
return ret;
}
void put_ans () {
for (int i = 0; i < n-1; i++) {
if (s[i] == 0)
continue;
s[i]--;
for (int j = i+1; j < n; j++) {
s[j]++;
for (int k = j; k < n; k++) {
s[k]++;
if (judge() == 0) {
printf(" %d %d %d\n", i, j, k);
return;
}
s[k]--;
}
s[j]--;
}
s[i]++;
}
}
int main () {
init();
int cas = 1;
while (scanf("%d", &n) == 1 && n) {
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
printf("Game %d:", cas++);
if (judge())
put_ans();
else
printf(" -1 -1 -1\n");
}
return 0;
}