复习了一下\(nim\)博弈.
判赢的\(nim\)异或和\(nim = a_{1} \oplus a_{2} \oplus a_{3} \oplus a_{4}\oplus \cdots \oplus a_{n}\)
0001
0010
0100
1000
其\(nim\)和为1111显然,所以先手必赢,那么先手如何赢?就是通过一个操作,让下一步该对面先手时,处于必败态。什么操作?就是让下一步对面面临着nim和为0,
首先要知道\(a \oplus b \oplus a = b\)所以可让\(t = nim \oplus a_{i}\)这样再判\(t\)是否小于\(a_{i}\),如果小于,那麽\(t\)一定可以从\(a_{i}\)取出来,如果不能,说明这堆不能操作,得找其他堆进行操作
我还想胡乱证明一下为什么nim和大于0,一定能找到一种方式,使得该对方先手时,nim积为0。
因为\(nim\)一定存在一个最高位,这是必然的,那么造成\(nim\)的这个最高位\(a\),他一定是也有这个最高位的,如果\(t = nim \oplus a_{i}\)那么\(t\)一定小于\(a\),也就是一定存在方案。
#include <iostream>
using namespace std;
int cas = 0;
int m;
int a[200099];
void solve() {
for (int i = 1; i <= m; i++)
cin >> a[i];
int nim = 0;
for (int i = 1; i <= m; i++)
nim ^= a[i];
if (nim == 0) {
cout << "No\n";
} else {
cout << "Yes\n";
for (int i = 1; i <= m; i++) {
int Nim = nim^a[i];
if (Nim < a[i]) {
cout << a[i] << " " << Nim << endl;
}
}
}
}
int main()
{
while (cin >> m) {
if (m == 0)return 0;
solve();
}
}
原文:https://www.cnblogs.com/Xiao-yan/p/14191621.html