Luogu P1247 取火柴游戏
题目链接 \(Click\) \(Here\)
这个题目其实就是一个\(Nim\)游戏的简单模型。对于单个的\(Nim\)游戏(单独一堆的情况),数学归纳可证其\(SG\)函数值等于其石子个数。所以对于组合起来的整个游戏,其\(SG\)函数值等于所有子游戏的异或和。如果这个值为\(0\)那么就是\(lose\),反之则有必胜策略。
对于必胜策略的要求:在采取必胜策略后,整个游戏的\(SG\)变为\(0\)。为此我们先统计最初状态的\(SG\),然后对于每一堆单独考虑:拆掉堆\(i\)的游戏为\(SG\)$w[i]$。要使得游戏$SG$变为$0$,就要异或上一个同样的值,即这一堆的石子要拿到$=SG$\(w[i]\)为为止。
#include <bits/stdc++.h>
using namespace std;
const int N = 500010;
int read () {
int s = 0, ch = getchar ();
while ('9' < ch || ch < '0') {
ch = getchar ();
}
while ('0' <= ch && ch <= '9') {
s = (s << 1) + (s << 3) + ch - '0';
ch = getchar ();
}
return s;
}
int n, w[N], sg;
int main () {
n = read ();
for (int i = 1; i <= n; ++i) {
w[i] = read ();
sg ^= w[i];
}
if (!sg) puts ("lose");
else {
for (int i = 1; i <= n; ++i) {
if (w[i] >= (sg ^ w[i])) {
cout << w[i] - (sg ^ w[i]) << " " << i << endl;
w[i] -= w[i] - (sg ^ w[i]);
for (int i = 1; i <= n; ++i) cout << w[i] << " ";
return 0;
}
}
}
}