Loading

AGC034F RNG and XOR(FWT,*)

AGC034F RNG and XOR

\(x\) 初始为 \(0\),每次会有 \(p_{i(/2 ^ N)}\) 的概率变成 \(x \oplus i\),问对于所有 \(0 \le k < 2 ^ N\)\(x\) 第一次变成 \(k\) 的期望次数。\(N \le 18\)

CODE

\(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
*/
posted @ 2022-11-08 18:48  Pizza1123  阅读(47)  评论(0)    收藏  举报