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;									
			}
		}
	}
}

posted @ 2019-03-11 09:01  maomao9173  阅读(129)  评论(0编辑  收藏  举报