题意:
给你可以一次取走的个数,和每堆的数量,求先手是否有必胜的方法,如果必胜则输出“W",没有则为”L"。
思路:
这是一道先求SG函数,然后利用SG函数来进行尼姆博弈的一道题。
SG函数是这样的:
每个点的SG函数都不等于能达到的前面点的SG值的最小非负整数值。(有点长,分开来就是,找到能一步到达到的SG点,把这些点的SG值放在集合D中,这个点的SG值就是不属于D点的值中最小的非负数。)
eg:
step[3] = 1, 2, 3(可以走1步、两步、三步)
点: 0 1 2 3 4 5 6 7 8 9 10
SG值:0 1 2 3 0 1 2 3 0 1 2
具体为什么:
首先得知道尼姆博弈中所有数异或的意义:
1.值等于0,说明此状态为必输。
2.值不为0,说明此状态为必胜。
3.在必胜状态下,通过适当的策略,可以使状态变为必输态(也就是把必输的情况留给了对手)
4.在必输状态下,不管通过什么策略,只能转化为必胜态(把必胜的局面留给对手)
5.在面对0的状态是必输态(通过题意)。
还是上面的例子,如果是 8 2,那么SG值异或就是 0 ^ 2 != 0,最终结果为胜,
如果是 8 4,那么SG值为 0 ^ 0 = 0,最终结果为输。
由此可以看到,凡是通过一定策略可以到达的点的SG值是不相等的,所以异或后不为0(必胜),
而不管通过什么策略都达不到的点(因为对手和你一样聪明,他会阻止你的,比如 8 -> 4就不行(自己想想)),SG值是相等的,异或后不为0(必输)
这就是SG+尼姆博弈的应用和具体意义。
Code:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<map>
#include<cctype>
#include<vector>
#define TEST
#define LL long long
#define Mt(f, x) memset(f, x, sizeof(f));
#define xep(i, n) for(int i = 0; i < (n); ++i)
#define rep(i, s, e) for(int i = (s); i <= (e); ++i)
#define dep(i, s, e) for(int i = (s); i >= (e); --i)
#ifdef TEST
#define See(a) cout << #a << " = " << a << endl;
#define See2(a, b) cout << #a << " = " << a << ' ' << #b << " = " << b << endl;
#define debug(a, s, e){ rep(_i, s, e) {cout << a[_i] << ' '; }cout << endl;}
#define debug2(a, s, e, ss, ee) rep(i_, s, e) {debug(a[i_], ss, ee);}
#else
#define See(a) {}
#define See2(a, b) {}
#define debug(a, s, e) {}
#define debug2(a, s, e, ss, ee) {}
#endif
const int MAX = 2e9;
const int MIN = -2e9;
const int PI = acos(-1.0);
const double eps = 1e-8;
using namespace std;
const int N = 10000 + 5;
int step[N], n;
int f[N];
int mex(int s)
{
bool v[105] = {};
for(int i = 0; i < n; ++i)
{
int t = s - step[i];
if(t < 0)
{
break;
}
if(f[t] == -1)
{
f[t] = mex(t);
}
v[f[t]] = true;
}
for(int i = 0; ; ++i)
{
if(!v[i])
{
return i;
}
}
}
int main()
{
while(~scanf("%d", &n) && n)
{
Mt(f, -1);
f[0] = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d", &step[i]);
}
sort(step, step + n);
int m;
scanf("%d", &m);
string ans = "";
while(m--)
{
int g;
scanf("%d", &g);
int tem = 0;
while(g--)
{
int a;
scanf("%d", &a);
if(f[a] == -1)
{
f[a] = mex(a);
}
tem ^= f[a];
}
if(tem == 0)
{
ans += "L";
}
else
{
ans += "W";
}
}
cout << ans << endl;
}
return 0;
}