CF850E Random Elections

发布时间 2023-07-21 08:29:57作者: Ender_32k

难点在于读题。

由于每个人有 \(6\) 种选法,答案其实就是某个人赢两次的方案数。

由于三个人本质没有差别,并且一种方案至多只有 \(1\) 个人赢两次。所以不妨设 A 赢了两次,答案就是方案数乘 \(3\)

考察 A 对于 B 和 C 的比赛,每个人的投票结果,第 \(i\) 个人的投票为 \(P_i\)\(Q_i\),有 \(P_i,Q_i\in \{0,1\}\)

  • \(P_i=0,Q_i=0\):获胜顺序为 \(C\to B\to A\) 或者 \(B\to C\to A\)
  • \(P_i=0,Q_i=1\):获胜顺序为 \(C\to A\to B\)
  • \(P_i=1,Q_i=0\):获胜顺序为 \(B\to A\to C\)
  • \(P_i=1,Q_i=1\):获胜顺序为 \(A\to B\to C\) 或者 \(A\to C\to B\)

显然只有当 \(P_i=Q_i\) 的时候贡献为 \(2\)。将所有位放到一起计算,每对 $(P,Q) $ 的贡献为 \(2^{n-\text{popcount(P \text{xor} Q)}}\)

\(c_k=\sum\limits_{i\ \text{xor}\ j=k}f_if_j\),答案显然就是 \(\sum\limits_{i=1}^{2^n-1}c_i2^{n-\text{popcount(i)}}\)

这就是个异或卷积,FWT 即可。复杂度 \(O(n2^n)\)

const int maxn = 22;
const int mod = 1e9 + 7;
const int T = (1 << 20) + 100;
int n, S, a[T], pt[T];

int qpow(int p, int q) {
    int res = 1;
    while (q) {
        if (q & 1) res = res * p % mod;
        p = p * p % mod, q >>= 1;
    }
    return res;
}

void fwt(int *s, int op) {
    for (int o = 2, k = 1; o <= S + 1; o <<= 1, k <<= 1)
        for (int i = 0; i <= S; i += o) 
            for (int j = 0; j < k; j++)
                (s[i + j] += s[i + j + k]) %= mod,
                s[i + j + k] = (a[i + j] - 2 * s[i + j + k] % mod + mod) % mod,
                (s[i + j + k] *= op) %= mod, (s[i + j] *= op) %= mod;
}

signed main() {
	n = read(), S = (1 << n) - 1;
    for (int i = 0; i <= S; i++) scanf("%1d", &a[i]);
    for (int i = 1; i <= S; i++) pt[i] = pt[i >> 1] + (i & 1);
    fwt(a, 1);
    for (int i = 0; i <= S; i++) (a[i] *= a[i]) %= mod;
    fwt(a, qpow(2, mod - 2));
    int ans = 0;
    for (int i = 0; i <= S; i++) 
        (ans += (1 << (n - pt[i])) * a[i] % mod) %= mod;
    write(3 * ans % mod);
    return 0;
}