SG定理的应用,SG[n]表示长度为n的空棋盘的mex值,可以根据第一个棋子的位置将棋盘分割,从较小的棋盘中递推得出,预处理出<=200的状态,然后根据题目所给的初始状态,会有一些地方预处理出来,然后把被分割的棋盘分别看做子游戏,利用SG定理求出函数值即可,要说明的是此题要求输出所有必胜策略的第一步输出,并不是把整个策略输出
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;
const int MAXN(210);
char str[MAXN];
bool can[MAXN], tcan[MAXN];
int SG[MAXN];
bool vis[MAXN];
int get_ans(bool *arr, int len)
{
int ret = 0, count = 0;
for(int i = 1; i <= len; ++i)
if(arr[i])
{
++count;
}
else
{
ret ^= SG[count];
count = 0;
}
ret ^= SG[count];
return ret;
}
int main()
{
int T;
scanf("%d", &T);
SG[0] = 0;
SG[1] = 1;
SG[2] = 1;
SG[3] = 1;
for(int i = 4; i <= 200; ++i)
{
memset(vis, 0, sizeof(vis));
for(int j = 3; j <= 5 && i-j >= 0; ++j)
vis[SG[i-j]] = true;
for(int j = 6; i-j >= 0; ++j)
vis[SG[j-5]^SG[i-j]] = true;
for(int j = 0; j <= 200; ++j)
if(!vis[j])
{
SG[i] = j;
break;
}
}
while(T--)
{
scanf("%s", str+1);
int len = strlen(str+1);
bool flag = false;
for(int i = 1; i <= len; ++i)
{
if(i > 2 && str[i-2] == 'X' && str[i-1] == 'X')
{
if(flag)
putchar(' ');
else
printf("WINNING\n");
printf("%d", i);
flag = true;
continue;
}
if(i > 1 && i < len && str[i-1] == 'X' && str[i+1] == 'X')
{
if(flag)
putchar(' ');
else
printf("WINNING\n");
printf("%d", i);
flag = true;
continue;
}
if(i < len-1 && str[i+1] == 'X' && str[i+2] == 'X')
{
if(flag)
putchar(' ');
else
printf("WINNING\n");
printf("%d", i);
flag = true;
continue;
}
}
if(flag)
putchar('\n');
else
{
memset(can, -1, sizeof(can));
for(int i = 1; i <= len; ++i)
if(str[i] == 'X')
{
for(int j = i-2; j <= i+2; ++j)
if(j >= 1 && j <= len)
can[j] = false;
}
int ans = get_ans(can, len);
if(ans != 0)
{
printf("WINNING\n");
bool print_space = false;
for(int i = 1; i <= len; ++i)
if(can[i])
{
memcpy(tcan, can, sizeof(tcan));
for(int j = i-2; j <= i+2; ++j)
if(j >= 1 && j <= len)
tcan[j] = false;
int tans = get_ans(tcan, len);
if(tans == 0)
{
if(print_space)
putchar(' ');
printf("%d", i);
print_space = true;
}
}
printf("\n");
}
else
printf("LOSING\n\n");
}
}
return 0;
}