一种不太快速计算多个少项式集合幂级数异或卷积的方法
fast_photon · · 算法·理论
首先求
考虑 FWT,要将
只要对数能求就能直接做。
如果有较多项呢?对于
复杂度
不能取对数的时候,考虑额外记录
以下是示例代码。由于没有高消,其累加复杂度是
#include<iostream>
#include<cstdio>
#include<fstream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<random>
#include<map>
#include<cassert>
#include<stack>
#define fopen(x, y) freopen(x".in", "r", stdin); freopen(y".out", "w", stdout);
#define int long long
#define pii pair<int, int>
#define fi first
#define se second
#ifdef int
#define inf 0x3f3f3f3f3f3f3f3fll
#else
#define inf 0x3f3f3f3f
#endif
#define maxB 65536
#define maxm 1048576
using namespace std;
//int m, M, mod, g, b, B, Mod;
const int m = 20, M = 1ll << m, mod = 998244353, g = 3, b = 16, B = 65536, Mod = 998244352ll * M;
inline int qpow(int x, int y) { int xum = 1; while(y) { if(y & 1) (xum *= x) %= mod; (x *= x) %= mod; y >>= 1; } return xum; }
int n, a, s[maxm], x[105], w[105], hfi[maxm], hse[maxm], ffi[maxm], fse[maxm];
int l3, l_1;
//void init_0();
void init_1();
int gxp(int x);
int gln(int x);
void fwt(int *f, int m, const int mod) {
const int M = 1ll << m;
for(int j = 0; j < m; j++) {
int L = 1ll << (j + 1), bL = 1ll << j;
for(int t = 0; t < M; t += L) {
int *x = &f[t], *y = x + bL;
for(int i = 0; i < bL; i++, x++, y++) {
(*x += *y) %= mod;
*y = (*x - (*y << 1)) % mod;
}
}
}
}
void work() {
// mod = 998244353; init_0();
init_1();
cin >> n;
for(int i = 1; i <= n; i++) {
int k;
cin >> k;
const int K = 1ll << k;
for(int j = 0; j < K; j++) hfi[j] = hse[j] = 0;
for(int j = 0; j < k; j++) {
cin >> x[j] >> w[j];
hfi[1ll << j] = w[j];
}
s[0] = 0;
for(int j = 1; j < K; j++) {
s[j] = s[j ^ (j & -j)] ^ x[__builtin_ctzll(j & -j)];
}
fwt(hfi, k, mod);
for(int j = 0; j < K; j++) {
(hfi[j] += mod) %= mod;
if(hfi[j] == 0) hse[j] = 1ll << (m - k);
else hfi[j] = (gln(hfi[j]) << (m - k)) % Mod;
}
fwt(hfi, k, Mod);
fwt(hse, k, Mod);
for(int j = 0; j < K; j++) {
(ffi[s[j]] += hfi[j]) %= Mod;
(fse[s[j]] += hse[j]) %= Mod;
}
}
fwt(ffi, m, Mod);
fwt(fse, m, Mod);
int sum = 0, iv = qpow(M, mod - 2);
for(int i = 0; i < M; i++) {
if(fse[i]) {
ffi[i] = 0;
continue;
}
(ffi[i] >>= m) %= (mod - 1);
if(ffi[i] < 0) ffi[i] += mod - 1;
ffi[i] = gxp(ffi[i]);
}
fwt(ffi, m, mod);
for(int i = 0; i < M; i++) {
(ffi[i] *= iv) %= mod;
cout << (ffi[i] + mod) % mod << ' ';
}
cout << '\n';
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0);
int _ = 1;
while(_--) work();
}
/*
void init_0() {
Mod = (mod - 1) * maxn;
vector<int> t;
int s = mod - 1;
B = 1, b = 0;
while(B * B < mod) B <<= 1, b++;
for(int i = 2; i * i <= s; i++) {
if(s % i == 0) {
while(s % i == 0) s /= i;
t.push_back(i);
}
}
for(int i = 2; i < mod; i++) {
int flg = 1;
for(int d : t) {
if(qpow(i, (mod - 1) / d) == 1) {
flg = 0;
break;
}
}
if(flg) {
g = i;
break;
}
}
}
//*/
int gb, gk[maxB], gbk[maxB];
pii gt[maxB + 1];
int find(int x) {
pii *p = lower_bound(gt, gt + B, make_pair(x, 0ll));
if(p->fi == x) return p->se;
return -1;
}
int gln(int x) {
int cnt = 0, p = find(x);
while(p == -1) {
(x *= gb) %= mod;
cnt++;
p = find(x);
}
return ((p - cnt * B) % (mod - 1) + (mod - 1)) % (mod - 1);
}
void init_1() {
gb = 1;
gk[0] = 1;
for(int i = 1; i < B; i++) gk[i] = gk[i - 1] * g % mod;
gb = gk[B - 1] * g % mod;
gbk[0] = 1;
for(int i = 1; i < B; i++) gbk[i] = gbk[i - 1] * gb % mod;
for(int i = 0; i < B; i++) gt[i] = make_pair(gk[i], i);
sort(gt, gt + B);
gt[B] = make_pair(mod, -1);
}
int gxp(int x) {
return gk[x & (B - 1)] * gbk[x >> b] % mod;
}