洛谷 P2197 nim游戏

题目分析

经典的 Nim 游戏

当 n 堆石子的数量异或和等于 0 时,先手必胜,否则先手必败。

证明
\(\oplus\)表示异或
Nim 游戏的必败态很显然,就是当前 n 堆石子的数量都为 0 的时候。
我们们用 \(a_i\) 来表示第i堆石子的数量,那么当前的局面就是:
\(0 \oplus 0 \oplus 0 \oplus 0 \oplus 0 \oplus 0 = 0\)

  • 对于先手来说,如果当前的局面为 \(a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_n = k\)

那么一定存在某个 \(a_i\) , 它的的二进制表示在最高位 k 上一定为 1
我们将 \(a_i \oplus k\) 就变成了

\[a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_n \oplus k = 0 \]

此时先手必胜。

  • 对于先手来说,如果当前的局面为 \(a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_n = 0\)

我们并不可以将一个 \(a_i\) 异或上一个数之后使得 \(a_1 \oplus a_2 \oplus a_3 \oplus \dots \oplus a_n = 0\)

此时先手必败。

code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 1010

using namespace std;
int T, a, b, ans;

int read() {
	int s = 0, f = 0; char ch = getchar();
	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

int main() {
	T = read();
	while (T--) {
		ans = 0;
		a = read();
		for (int i = 1; i <= a; i++)
			b = read(), ans ^= b;
		if (!ans) puts("No");
		else puts("Yes");
	}
	return 0;
}
posted @ 2020-09-07 09:46  Kersen  阅读(116)  评论(0编辑  收藏  举报