集合幂级数

算法

\(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;
    }
}

猜你喜欢

转载自www.cnblogs.com/King-George/p/9298685.html
今日推荐