就是 AcWing 893.集合-Nim游戏 加一个先手必胜时的具体解。
我们知道当所有子游戏 sg 函数的异或和非 0 时为先手必胜,是 0 则先手必败。那么只要先手取完之后让 sg 值变成 0 即可。所以我们暴力枚举就好了。注意一下异或符号和判等符号的优先级,打一下括号就行。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <unordered_set>
const int N = 110, M = 11010;
int m, n;
int s[N], sg[M], a[N];
int get_sg(int x)
{
if (sg[x] >= 0)
return sg[x];
std::unordered_set<int> S;
for (int i = 1; i <= m; ++i)
if (x >= s[i])
S.insert(get_sg(x - s[i]));
for (int i = 0; i <= S.size(); ++i)
if (!S.count(i))
return sg[x] = i;
return sg[x] = -1;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
scanf("%d", &m);
for (int i = 1; i <= m; ++i)
scanf("%d", &s[i]);
int ans = 0;
memset(sg, -1, sizeof(sg));
for (int i = 1; i <= n; ++i)
ans ^= get_sg(a[i]);
puts(ans ? "YES" : "NO");
if (ans)
{
bool fin = 0;
for (int i = 1; i <= n && !fin; ++i)
for (int j = 1; j <= m && s[j] <= a[i] && !fin; ++j)
if ((ans ^ get_sg(a[i]) ^ get_sg(a[i] - s[j])) == 0)
fin = 1, printf("%d %d\n", i, s[j]);
}
}