\(x\) 初始为 \(0\),每次会有 \(p_{i(/2 ^ N)}\) 的概率变成 \(x \oplus i\),问对于所有 \(0 \le k < 2 ^ N\),\(x\) 第一次变成 \(k\) 的期望次数。\(N \le 18\)。
设 \(f_i\) 表示 \(i\) 的期望次数。
\[\forall i \neq 0 : f_i = \sum_{j = 0} ^ {2 ^ N - 1} f_{i \oplus j} p_j \]FWT 转集合幂级数:
\[F = FP + I - c \]代入多项式的和可得:\(c = 2 ^ N\)。
于是 \(F = \frac{2 ^ N - I}{P - 1}\)。\(f_0\) 还是会被算错,所以最后所有 \(f_i \leftarrow f_i - f_0\)。
集合幂级数乘法逆就是先 FWT 然后求逆点值。
#include <bits/stdc++.h>
using namespace std;
constexpr int mod = 998244353;
void sub(int& x) {
if (x >= mod) x -= mod;
}
int power(int a, int x = mod - 2) {
int res = 1;
while (x) {
if (x & 1) res = (long long)res * a % mod;
x >>= 1;
a = (long long)a * a % mod;
}
return res;
}
void fwt(vector<int>& a) {
for (unsigned int k = 1; k < a.size(); k *= 2) for (unsigned int i = 0; i < a.size(); i += k * 2) for (unsigned int j = 0; j < k; ++j) {
int x = a[i | j], y = a[i | k | j];
sub(a[i | j] = x + y);
sub(a[i | k | j] = x - y + mod);
}
}
void ifwt(vector<int>& a) {
fwt(a);
int inv = power(a.size());
for (unsigned int i = 0; i < a.size(); ++i) a[i] = (long long)a[i] * inv % mod;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
N = 1 << N;
vector<int> p(N);
for (int i = 0; i < N; ++i) cin >> p[i];
int invp = power(accumulate(p.begin(), p.end(), 0ll) % mod);
for (int i = 0; i < N; ++i) p[i] = (long long)p[i] * invp % mod;
sub(p[0] += mod - 1);
vector<int> a(N, mod - 1);
sub(a[0] += N);
fwt(a);
fwt(p);
for (int i = 0; i < N; ++i) a[i] = (long long)a[i] * power(p[i]) % mod;
ifwt(a);
for (int i = N - 1; i >= 0; --i) sub(a[i] += mod - a[0]);
for (int i = 0; i < N; ++i) cout << a[i] << '\n';
}
/*
3.00s 1.00GB
*/
标签:XOR,sub,int,AGC034F,long,++,FWT,mod
From: https://www.cnblogs.com/Pizza1123/p/16870805.html