[poly] 付公主的背包

\(\texttt{link}\)

每个体积为 \(v\) 的物品可以看作生成函数 \(\dfrac 1 {1-x^v}\),答案即为这些生成函数的积的 \([0,m]\) 项的系数。

暴力做的复杂度为 \(O(nm\log m)\),考虑先 \(\ln\) 再相加最后 \(\exp\) 回去。

\(\ln(\dfrac 1 {1-x^v}) = \ln 1 - \ln(1-x^v) = -\ln(1-x^v)\)

\(f(x) = 1-x^v,G(f(x)) = \ln f(x)\)

求导,\(G'(f(x)) = \dfrac{f'(x)}{f(x)} = \dfrac{-vx^{v-1}}{1-x^v} = -vx^{v-1}\sum\limits_{i=0}^{+\infty}x^{iv} = \sum\limits_{i=0}^{+\infty}-vx^{(i+1)v-1} = \sum\limits_{i=1}^{+\infty}-vx^{iv-1}\)

积分回去就是 \(G(f(x)) = \sum\limits_{i=1}^{+\infty}-\dfrac 1 {i}x^{iv}\)

然后就可以做了,时间复杂度 \(\mathrm{O(m\log m)}\)

\(\texttt{Code:}\)

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int cmd = 998244353;
int read() {
    int x = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= c == '-', c = getchar();
    while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
    return f ? -x : x;
}
int fpow(int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = 1ll * a * a % cmd)
        if (b & 1) res = 1ll * res * a % cmd;
    return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
const int N = (1 << 18) + 5;
int n, m, f[N], v[N], cnt[N];
namespace Poly {
    int yg = 3, invyg = fpow(3, cmd - 2), rev[N], w[N], inv[N];
    void ntt(int *f, int n, int tp) {
        for (int i = 1; i < n; i++) {
            rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
            if (i < rev[i]) swap(f[i], f[rev[i]]);
        }
        for (int len = 2; len <= n; len <<= 1) {
            int w0 = fpow(tp ? yg : invyg, (cmd - 1) / len); w[0] = 1;
            for (int i = 1; i < (len >> 1); i++) w[i] = 1ll * w[i - 1] * w0 % cmd;
            for (int s = 0; s < n; s += len)
            for (int i = 0; i < (len >> 1); i++) {
                int cur = 1ll * w[i] * f[s + (len >> 1) + i] % cmd;
                f[s + (len >> 1) + i] = sub(f[s + i], cur);
                f[s + i] = add(f[s + i], cur);
            }
        }
        if (!tp) {
            int invn = fpow(n, cmd - 2);
            for (int i = 0; i < n; i++) f[i] = 1ll * f[i] * invn % cmd;
        }
    }
    void tms(int *f, int *g, int n) {
        for (int i = 0; i < n; i++) f[i] = 1ll * f[i] * g[i] % cmd;
    }
    void NTT(int *f, int *g, int n) {
        ntt(f, n << 1, 1); ntt(g, n << 1, 1);
        tms(f, g, n << 1); ntt(f, n << 1, 0);
        memset(f + n, 0, sizeof(int)*n);
        memset(g, 0, sizeof(int)*(n << 1));
    }
    void init(int n) {
        inv[1] = 1;
        for (int i = 2; i <= n; i++)
            inv[i] = 1ll * (cmd - cmd / i) * inv[cmd % i] % cmd;
    }
    void qiudao(int *f, int n) {
        for (int i = 1; i < n; i++) f[i - 1] = 1ll * i * f[i] % cmd;
        f[n - 1] = 0;
    }
    void jifen(int *f, int n) {
        for (int i = n - 2; ~i; i--) f[i + 1] = 1ll * f[i] * inv[i + 1] % cmd;
        f[0] = 0;
    }
    void invp(int *f, int n) {
        static int A[N], B[N], C[N];
        A[0] = fpow(f[0], cmd - 2);
        for (int len = 2; len <= n; len <<= 1) {
            for (int i = 0; i < (len >> 1); i++)
                B[i] = (A[i] << 1) % cmd;
            memcpy(C, f, sizeof(int)*len);
            ntt(A, len << 1, 1); tms(A, A, len << 1);
            ntt(C, len << 1, 1); tms(A, C, len << 1);
            ntt(A, len << 1, 0);
            memset(A + len, 0, sizeof(int)*len);
            for (int i = 0; i < len; i++)
                A[i] = sub(B[i], A[i]);
        }memcpy(f, A, sizeof(int)*n);
        memset(A, 0, sizeof(int)*n);
        memset(B, 0, sizeof(int)*n);
        memset(C, 0, sizeof(int)*(n << 1));
    }
    void lnp(int *f, int m) {
        static int g[N];
        memcpy(g, f, sizeof(int)*m);
        qiudao(f, m); invp(g, m);
        NTT(f, g, m); jifen(f, m);
        memset(g, 0, sizeof(int)*m);
    }
    void exp(int *f, int n) {
        static int A1[N], A2[N];
        A1[0] = 1;
        for (int len = 2; len <= n; len <<= 1) {
            memcpy(A2, A1, sizeof(int)*(len >> 1));
            lnp(A2, len);
            for (int i = 0; i < len; i++) A2[i] = sub(f[i], A2[i]);
            A2[0] = add(A2[0], 1);
            NTT(A1, A2, len);
        }memcpy(f, A1, sizeof(int)*n);
        memset(A1, 0, sizeof(int)*n);
        memset(A2, 0, sizeof(int)*n);
    }
}using namespace Poly;
int main() {
    #ifdef LOCAL
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
    #endif
    n = read(); m = read();
    for (int i = 1; i <= n; i++) cnt[v[i] = read()]++;
    sort(v + 1, v + n + 1);
    int tot = unique(v + 1, v + n + 1) - v - 1;
    int len = 1; for (; len <= m; len <<= 1);
    init(len);
    for (int i = 1; i <= tot; i++) {
        for (int j = 1; v[i] * j <= m; j++)
            f[v[i] * j] = add(f[v[i] * j], 1ll * cnt[v[i]] * inv[j] % cmd);
    }
    exp(f, len);
    for (int i = 1; i <= m; i++) printf("%d\n", f[i]);
    return 0;
}
posted @ 2021-12-17 19:56  klii  阅读(43)  评论(0)    收藏  举报