题目链接:https://cn.vjudge.net/problem/UVA-10561
题意:有n个格子排成一排,其中一些格子里面有字符X,两个游戏者轮流操作,每次可以选一个空格,在里面放字符X,如果此时有3个X连续X出现,则该游戏者赢得比赛,判断先手必胜还是必败,如果必胜输出所有毕生策略。
题解:初始局面下,一个X的左两个到右2个都不能放,这些都是禁区,一旦放,那么先手必败,这样我们先处理出所有禁区,然后就剩被禁区分割的区域,在这些区域游戏,谁不能放X,谁就必须在禁区放,那么下一个操作的人胜利。
在若干个区域游戏,那么就可以看成若干个游戏的和,那么在宏观上,我们求出每个子游戏的SG函数,然后求出总游戏的SG函数,也就是各子游戏SG函数的Nim和,就可以判断一个局面能的胜负,题中还让我们输出所有的先手胜利的策略,这个直接枚举每一位就可以。
SG(i)表示在连续i块的区域进行游戏的SG函数值。
代码:
# define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(2)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#define inf 0x3f3f3f3f
#define Pair pair<int,int>
//#define int long long
#define fir first
#define sec second
namespace fastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
//fread->read
bool IOerror = 0;
//inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
inline char nc() {
static char buf[BUF_SIZE], * p1 = buf + BUF_SIZE, * pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf; pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) { IOerror = 1; return -1; }
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template<class T> inline bool read(T& x) {
bool sign = 0; char ch = nc(); x = 0;
for (; blank(ch); ch = nc());
if (IOerror)return false;
if (ch == '-')sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0';
if (sign)x = -x;
return true;
}
inline bool read(double& x) {
bool sign = 0; char ch = nc(); x = 0;
for (; blank(ch); ch = nc());
if (IOerror)return false;
if (ch == '-')sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0';
if (ch == '.') { double tmp = 1; ch = nc(); for (; ch >= '0' && ch <= '9'; ch = nc())tmp /= 10.0, x += tmp * (ch - '0'); }
if (sign)x = -x; return true;
}
inline bool read(char* s) {
char ch = nc();
for (; blank(ch); ch = nc());
if (IOerror)return false;
for (; !blank(ch) && !IOerror; ch = nc())* s++ = ch;
*s = 0;
return true;
}
inline bool read(char& c) {
for (c = nc(); blank(c); c = nc());
if (IOerror) { c = -1; return false; }
return true;
}
template<class T, class... U>bool read(T& h, U& ... t) { return read(h) && read(t...); }
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
/*---------------------------------------------------------------------------------------------------------------------------*/
const double eps = 1e-8;
struct Point { double x, y; Point(double x = 0, double y = 0) :x(x), y(y) {} };
typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.x, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x * p, A.y * p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
bool operator < (const Point& A, const Point& B) { return A.x < B.x || (A.x == B.x && A.y < B.y); }
int dcmp(double x) { if (fabs(x) < eps)return 0; else return x < 0 ? -1 : 1; }
bool operator == (const Point& A, const Point& B) { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }
double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }
double Length(Vector A) { return sqrt(Dot(A, A)); }
double Dist2(const Point& A, const Point& B) { return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y); }
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }
double Area2(Point A, Point B, Point C) { return Cross(B - A, C - A); }
double DistanceToLine(Point P, Point A, Point B) { Vector v1 = B - A, v2 = P - A; return fabs(Cross(v1, v2)) / Length(v1); }
Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y / L, A.x / L); }
Vector Rotate(Vector A, double rad) { return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad)); }
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) { Vector u = P - Q; double t = Cross(w, u) / Cross(v, w); return P + v * t; }
double PolygonArea(vector<Point>p) {//duo area
double area = 0;
int n = p.size();
for (int i = 1; i < n - 1; i++)area += Cross(p[i] - p[0], p[i + 1] - p[0]);
return area / 2;
}
double torad(double deg) { return deg / 180 * acos(-1); }
vector<Point> ConvexHull(vector<Point>& p) {
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
int n = p.size();
int m = 0;
vector<Point> ch(n + 1);
for (int i = 0; i < n; i++) { while (m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m--; ch[m++] = p[i]; }
int k = m;
for (int i = n - 2; i >= 0; i--) { while (m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m--; ch[m++] = p[i]; }
if (n > 1)m--;
ch.resize(m);
return ch;
}
double diameter2(vector<Point>& points, Point& A, Point& B) {
vector<Point>p = ConvexHull(points);
int n = p.size();
if (n == 1) return 0;
if (n == 2) return Dist2(p[0], p[1]);
//p.push_back(p[0]); // 免得取模
double ans = 0;
for (int u = 0, v = 1; u < n; u++) {
for (;;) {
//Cross(p[u+1]-p[u],p[v+1]-p[v])<=0时停止旋转
int diff = Cross(p[u + 1] - p[u], p[v + 1] - p[v]);
if (diff <= 0) {
if (Dist2(p[u], p[v]) > ans) {
ans = Dist2(p[u], p[v]); // u和v是对踵点
A = p[u]; B = p[v];
}
//if(diff==0) ans=max(ans,Dist2(p[u],p[v+1])); // diff==0 时u和v+1也是对踵点
break;
}
v = (v + 1) % n;
}
}
return ans;
}
/*---------------------------------------------------------------------------------------------------------------------------*/
struct Line {
Point P;
Vector v;
double ang;
Line() {}
Line(Point P, Vector v) :P(P), v(v) { ang = atan2(v.y, v.x); }
bool operator < (const Line& L)const {
return ang < L.ang;
}
};
Point GetLineIntersection(const Line& a, const Line& b) {
Vector u = a.P - b.P;
double t = Cross(b.v, u) / Cross(a.v, b.v);
return a.P + a.v * t;
}
bool OnLeft(Line L, Point p) { return Cross(L.v, p - L.P) > 0; }
vector<Point>HalfplaneIntersection(vector<Line>L) {
int n = L.size();
sort(L.begin(), L.end());
int first, last;
vector<Point> p(n);
vector<Line> q(n);
vector<Point> ans;
q[first = last = 0] = L[0];
for (int i = 1; i < n; i++) {
while (first < last && !OnLeft(L[i], p[last - 1])) last--;
while (first < last && !OnLeft(L[i], p[first]))first++;
q[++last] = L[i];
if (fabs(Cross(q[last].v, q[last - 1].v)) < eps) {
last--;
if (OnLeft(q[last], L[i].P))q[last] = L[i];
}
if (first < last)p[last - 1] = GetLineIntersection(q[last - 1], q[last]);
}
while (first < last && !OnLeft(q[first], p[last - 1]))last--;//删除无用平面
if (last - first <= 1)return ans;
p[last] = GetLineIntersection(q[last], q[first]);//计算首尾两个半平面的交点
//从deque复制到输出中
for (int i = first; i <= last; i++)ans.push_back(p[i]);
return ans;
}
bool OnSegment(const Point& p, const Point& a1, const Point& a2) {
return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}
bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {
double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1),
c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}
int IsPointInPolygon(const Point& p, const vector<Point>& poly) {
int wn = 0;
int n = poly.size();
for (int i = 0; i < n; i++) {
const Point& p1 = poly[i];
const Point& p2 = poly[(i + 1) % n];
if (p1 == p || p2 == p || OnSegment(p, p1, p2)) return -1; // 在边界上
int k = dcmp(Cross(p2 - p1, p - p1));
int d1 = dcmp(p1.y - p.y);
int d2 = dcmp(p2.y - p.y);
if (k > 0 && d1 <= 0 && d2 > 0) wn++;
if (k < 0 && d2 <= 0 && d1 > 0) wn--;
}
if (wn != 0) return 1; // 内部
return 0; // 外部
}
bool ConvexPolygonDisjoint(const vector<Point> ch1, const vector<Point> ch2) {
int c1 = ch1.size();
int c2 = ch2.size();
cout << "c1 " << c1 << " " << "c2 " << c2 << endl;
for (int i = 0; i < c1; i++)
if (IsPointInPolygon(ch1[i], ch2) != 0) return false; // 内部或边界上
for (int i = 0; i < c2; i++)
if (IsPointInPolygon(ch2[i], ch1) != 0) return false; // 内部或边界上
for (int i = 0; i < c1; i++)
for (int j = 0; j < c2; j++)
if (SegmentProperIntersection(ch1[i], ch1[(i + 1) % c1], ch2[j], ch2[(j + 1) % c2])) return false;
return true;
}
/*---------------------------------------------------------------------------------------------------------------------------*/
const int N = 200 + 5;
const double pi = acos(-1.0);
typedef long long ll;
//const int mod = 998244353;
int sg[N];
char state[N];
bool slove(char state[]) {
int len = strlen(state);
for (int i = 0; i < len - 2; i++)
if (state[i] == 'X' && state[i + 1] == 'X' && state[i + 2] == 'X')return false;
bool book[N];
memset(book, 0, sizeof book);
book[len] = 1;
for (int i = 0; i < len; i++) {
if (state[i] == 'X') {
for (int d = -2; d <= 2; d++) {
if (i + d >= 0 && i + d < len) {
if (d != 0 && state[i + d] == 'X')return true;
book[i + d] = 1;
}
}
}
}
int SG = 0;
int start = -1;
for (int i = 0; i <= len; i++) {
if (start < 0 && !book[i])start = i;
if (start >= 0 && book[i])SG ^= sg[i - start];
if (book[i])start = -1;
}
return SG != 0;
}
int mex(vector<int>ve) {
if (ve.empty())return 0;
sort(ve.begin(), ve.end());
if (ve[0] != 0)return 0;
for (int i = 0; i < ve.size() - 1; i++)
if (ve[i + 1] - ve[i] > 1)return ve[i] + 1;
return ve[ve.size() - 1] + 1;
}
void getSG() {
sg[0] = 0;
sg[1] = sg[2] = sg[3] = 1;
for (int i = 4; i < N; i++) {
vector<int>ve;
ve.push_back(sg[i - 3]);//1
ve.push_back(sg[i - 4]);//2
if (i >= 5)ve.push_back(sg[i - 5]);//3
for (int j = 4; j <= i - 2; j++)
ve.push_back(sg[j - 3] ^ sg[i - j - 2]);
sg[i] = mex(ve);
}
}
signed main() {
getSG();
int t;
scanf("%d", &t);
while (t--) {
scanf("%s", state);
if (!slove(state))puts("LOSING\n");
else {
vector<int>ve;
puts("WINNING");
int len = strlen(state);
for (int i = 0; i < len; i++) {
if (state[i] == '.') {
state[i] = 'X';
if (!slove(state))ve.push_back(i + 1);
state[i] = '.';
}
}
printf("%d", ve[0]);
for (int i = 1; i < ve.size(); i++)
printf(" %d", ve[i]);
puts("");
}
}
return 0;
}