CF850E Random Elections
难点在于读题。
由于每个人有 \(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;
}