Solution - Codeforces 662A Gambling Nim
首先 Nim 游戏的结论是所有值异或起来得到的值不为 \(0\) 就先手必胜。
对于要么选 \(a_i\) 要么选 \(b_i\) 其实是并不希望看到的。
实际上更希望看到的是不选或者选一个数的情况。
因为 \(a_i \oplus (a_i\oplus b_i) = b_i\)。
于是令 \(w = \bigoplus_{i = 1}^n a_i, c_i = a_i\oplus b_i\)。
那么题目就变为了有 \(\frac{1}{2}\) 的概率让 \(w\) 异或上 \(c_i\),问最终 \(w > 0\) 的概率。
但是 \(w > 0\) 不是很好做,考虑反着考虑 \(w = 0\) 的概率减掉。
对于这类多个元素的异或,一个想法是建出异或线性基。
那么如果 \(w\) 都无法被线性基里的元素表示出,那么 \(w\) 就不可能异或成 \(0\),所以 \(w > 0\) 的概率就为 \(1\)。
否则如果 \(w\) 能被表示出,记非自由元(非 \(0\))的元素个数为 \(c\)。
对于自由元,不管怎么异或值都不会发生改变,于是这些并不需要去考虑。
对于非自由元,因为线性基的定义可以知道 \(w\) 只有可能被一种选择表示出,于是 \(w = 0\) 的概率就是 \(\frac{1}{2^c}\),那么 \(w > 0\) 的概率就是 \(\frac{2^c - 1}{2^c}\)。
时间复杂度 \(\mathcal{O}(n\log V)\)。
#include<bits/stdc++.h>
using ll = long long;
constexpr ll mod = 5e5 + 10;
constexpr int maxn = 5e5 + 10;
ll a[maxn];
int main() {
int n;
scanf("%d", &n);
ll x = 0;
for (int i = 1; i <= n; i++) {
ll y, z;
scanf("%lld%lld", &y, &z);
x ^= y, a[i] = y ^ z;
}
int c = 0;
for (int w = 59, i = 1; ~ w; w--) {
for (int j = i; j <= n; j++) {
if (a[j] >> w & 1ll) {
std::swap(a[i], a[j]);
}
}
if (~ a[i] >> w & 1ll) continue;
for (int j = i + 1; j <= n; j++) {
if (a[j] >> w & 1ll) {
a[j] ^= a[i];
}
}
if (x >> w & 1ll) x ^= a[i];
i++, c++;
}
if (x) {
printf("1/1");
} else {
printf("%lld/%lld", (1ll << c) - 1, 1ll << c);
}
return 0;
}