算法
\(c_k\ =\ \sum_{i,\ j}\ [i\ or\ j\ =\ k]\ [i\ and\ j\ =\ 0]\ a_i\ b_j\)。
考虑 \(c_k\ =\ \sum_{i,\ j}\ [i\ or\ j\ =\ k]\ a_i\ b_j\),反演后得到 \(A_{0,\ 1,\ ...,\ n\ -\ 1},\ B_{0,\ 1,\ ...,\ n\ -\ 1}\)。
类似的,将 \(a_i\) 写成多项式的形式 \(a_i(x)\ =\ \sum_{j\ =\ 0}^{log2(n)}\ [j\ =\ bit(i)]\ a_i\ x^i\),\(A,\ B\) 为对 \(a,\ b\) 反演得到的多项式,\(c_i\ =\ [x^{bit(i)}]\ c_i(x)\) 即可,其中 \(bit(i)\) 为c++中 __builtin_popcount(i)。
应用
代码
FMT
FMT
const int maxn = (1 << 19) | 10, maxm = 20, mod = 998244353; // deal with n <= 2**19
namespace FMT {
const unsigned long long LIM = 17e18, MOD = LIM / (unsigned long long) mod * (unsigned long long) mod;
int n, m, A[maxn][maxm], B[maxn][maxm], C[maxn][maxm];
void upd(int &x, const int &y) { x += y; if(x >= mod) x -= mod; return; }
void trans(int f[maxn][maxm]) {
for (int hl = 1, l = 2; l <= n; hl = l, l <<= 1) for (int i = 0; i < n; i += l) for (int j = 0; j < hl; ++j) for (int k = 0; k <= m; ++k) upd(f[i + j + hl][k], f[i + j][k]);
return;
}
void itrans(int f[maxn][maxm]) {
for (int hl = 1, l = 2; l <= n; hl = l, l <<= 1) for (int i = 0; i < n; i += l) for (int j = 0; j < hl; ++j) for (int k = 0; k <= m; ++k) upd(f[i + j + hl][k], mod - f[i + j][k]);
return;
}
void mul(int *a, int *b, int *c) {
for (int i = 0; i <= m; ++i) {
unsigned long long t = 0;
for (int j = 0; j <= i; ++j) {
t += (unsigned long long) a[i - j] * b[j];
if(t >= LIM) t -= MOD;
}
c[i] = t % mod;
}
return;
}
void work(int _n, int *a, int *b, int *c) {
n = _n; m = 0; while((1 << m) < n) ++m;
if(m <= 3) {
memset(c, 0, sizeof(c[0]) * n);
for (int i = 0; i < n; ++i) for (int x = a[i], t = (n - 1 ^ i), j = t; ; j = (j - 1 & t)) {
c[i | j] = ((long long) x * b[j] + c[i | j]) % mod;
if(!j) break;
}
return;
}
for (int i = 0; i < n; ++i) memset(A[i], 0, sizeof(A[i][0]) * (m + 1)), A[i][__builtin_popcount(i)] = (a[i] + mod) % mod; trans(A);
for (int i = 0; i < n; ++i) memset(B[i], 0, sizeof(B[i][0]) * (m + 1)), B[i][__builtin_popcount(i)] = (b[i] + mod) % mod; trans(B);
for (int i = 0; i < n; ++i) mul(A[i], B[i], C[i]);
itrans(C); for(int i = 0; i < n; ++i) c[i] = C[i][__builtin_popcount(i)];
return;
}
}