Loading

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;
}
posted @ 2024-11-22 09:03  rizynvu  阅读(3)  评论(0编辑  收藏  举报