Codeforces-850E Random Elections

Description

有三个人 \(A, B, C\) 参加选举。有 \(n\) 个选民,每个选民都有一个投票顺序 \(b\)\(b(X)\) 表示 \(X\)(显然 \(X\in\{A, B, C\}\))在其心中的排名。有 \(\{b(A), b(B), b(C)\}=\{1, 2, 3\}\)

\(X\) 对决 \(Y\) 时会得到一个 01 序列 \(x_1, x_2, \cdots, x_n\),其中 \(x_i=[b(X)<b(Y)]\)。题目还会给定一个函数 \(f\),含义是若 \(f(x)=1\) 那么 \(X\) 就赢了。函数 \(f\)\(2^n\)\(x\) 的取值对应的结果都会给定,并保证 \(f(x_1, x_2, \cdots, x_n)=1-f(1-x_1, 1-x_2, \cdots , 1-x_n)\)

求在所有 \(b\) 的情况中,随机选定一种后,\(A, B, C\) 三人中两两对决,其中有一个人赢了两次的概率 \(\times 6^n\) 的结果(可以证明为整数)\(\bmod (10^9+7)\) 的值

Hint

\(1\le n\le 20\) 为什么只有 20 个选民

Solution

根本没思路/dk

由于三个人的地位相同,不妨假定 \(A\) 对决 \(B, C\),然后对求出的结果 \(\times 3\) 即为答案。

\(A\to B, A\to C\) 得到的两个 01 序列分别为 \(a, b\)。如果 \(A\) 要全部都赢,那么得有 \(f(a)=f(b)=1\)

考虑第 \(i\) 个人的情况 \(a_i\)\(b_i\),如果 \(a_i=0,b_i=1\),那么说明 \(b(B) < b(A) < b(C)\),这三个人在 \(i\) 心中的顺序已经被确定,同理 \(a_i=1, b_i=0\) 的情况也是如此。

反之,如果 \(a_i=b_i\),不论两者是零是一,都只能说明 \(b(A)\) 同时小于或同时大于 \(b(B)\)\(b(C)\),至于 \(b(B)\)\(b(C)\) 的大小关系还没有办法确定,那么还存在两种可能的情况。

小结一下:如果 \(a_i \ne b_i\),那么第 \(i\) 个人的 \(b\) 只有一种可能,反之就是两种。对于序列 \(a, b\) 而言,对于所有 \(a_i\ne b_i\) 的人都快存在两种情况,也就是一共 \(2^{\sum_i[a_i\ne b_i]}\) 中可能。

上面那个 \(\sum_i[a_i\ne b_i]\) 太难搞了,我们若是将 \(a, b\) 直接理解为两个二进制数,那么就是 \(2^{n-\text{popcount}(a\oplus b)}\)\(\oplus\) 为异或,\(\text{popcount}(x)\) 表示 \(x\) 中 1 的个数)。

最终统计答案的式子,就直接枚举 \(a, b\)

\[\sum_{a, b\in [0, 2^n)} 2^{n-\text{popcount}(a\oplus b)}\times f(a)\times f(b) \]

改枚举 \(a, b\) 为枚举 \(a\oplus b\),就有:

\[\sum_{x\in [0, 2^n)} 2^{n-\text{popcount}(x)}\sum_{a\oplus b=x}f(a)\times f(b) \]

\(g(x)=\sum_{a\oplus b=x}f(a)\times f(b)\),发现这是一个异或卷积,可以 FWT 搞出来 \(g\)。于是做完了。

复杂度 \(O(n\times 2^n)\)

/*
 * Author : _Wallace_
 * Source : https://www.cnblogs.com/-Wallace-/
 * Problem : Codeforces 850E Random Elections
 */
#include <cstdio>

const int mod = 1e9 + 7, inv2 = (mod + 1) >> 1;
inline int& reduce(int& x) { return x >= mod ? x -= mod : x; }
void fwt(int* f, int n, bool flag) {
  for (int p = 2, q = 1; p <= (1 << n); q = (p <<= 1) >> 1)
    for (int i = 0; i < (1 << n); i += p)
      for (int x, y, j = i; j < i + q; j++) {
        x = f[j], y = f[j + q], reduce(f[j] = x + y), reduce(f[j + q] = x - y + mod);
        if (flag) f[j] = (f[j] * 1ll * inv2) % mod, f[j + q] = (f[j + q] * 1ll * inv2) % mod;
      }
}

const int N = 20;
int n, f[1 << N];

signed main() {
  static char s[1 << N]; scanf("%d%s", &n, s);
  for (int i = 0; i < (1 << n); i++) f[i] = s[i] - '0';

  fwt(f, n, 0);
  for (int i = 0; i < (1 << n); i++)
    f[i] = (f[i] * 1ll * f[i]) % mod;
  fwt(f, n, 1);

  int ans = 0;
  for (int i = 0; i < (1 << n); i++)
    reduce(ans += (f[i] * 1ll * (1 << (n - __builtin_popcount(i)))) % mod);
  return printf("%lld\n", ans * 3ll % mod), 0;
}
posted @ 2020-12-20 20:05  -Wallace-  阅读(289)  评论(0编辑  收藏  举报