1. 程式人生 > >洛谷 P4389: 付公主的背包

洛谷 P4389: 付公主的背包

floor lin pla 生成 spl display lld 需要 aligned

題目傳送門:洛谷 P4389。

題意簡述:

\(n\) 個物品,每個物品都有無限多,第 \(i\) 個物品的體積為 \(v_i\)\(v_i\le m\))。

問用這些物品恰好裝滿容量為 \(i\) 的背包的方案數,兩個方案不同當且僅當存在某一個物品的選取數量不同。

你需要對 \(i\in [1,m]\) 回答,答案對 \(998,244,353\) 取模。

題解:

對於一個體積為 \(v\) 的物品,它裝滿容量為 \(x\) 的背包的方案數序列為 \(a_x=[v|x]\)

例如 \(v=3\) 時有序列(從 \(0\) 開始):\(\{1,0,0,1,0,0,1,0,0,1,0,\cdots\}\)

它的普通生成函數為 \(\frac{1}{1-x^v}\)

記答案的普通生成函數為 \(F\),則有 \(F=\prod_{i=1}^{n}\frac{1}{1-x^{v_i}}\)

兩邊取對數:\(\ln F=\sum_{i=1}^{n}\ln\frac{1}{1-x^{v_i}}\)

有一個式子:\(\ln\frac{1}{1-x^k}=\sum_{i=1}^{\infty}\frac{1}{i}x^{ik}\)

這個式子的證明:

\(f(x)=\frac{1}{1-x^k}\),設 \(g(x)=\ln f\)

\[\begin{aligned}g(x)&=\ln f(x)\\&=\int(\frac{\mathrm{d}}{\mathrm{d}x}\ln f)(x)\mathrm{d}x\\&=\int(\frac{f‘(x)}{f(x)})\mathrm{d}x\\&=\int((1-x^k)f‘(x))\mathrm{d}x\\&=\int((1-x^k)\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1})\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}-\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}\cdot x^k)\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}-\sum_{i=1}^{\infty}k\cdot (i-1)\cdot x^{ki-1})\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot x^{ki-1})\mathrm{d}x\\&=\sum_{i=1}^{\infty}\frac{1}{i}x^{ki}\end{aligned}\]

建議背一些常用式子。

那麽就顯而易見了:

\[\begin{aligned}\ln F&=\sum_{i=1}^{n}\sum_{j=1}^{\infty}\frac{1}{j}x^{v_{i}j}\\&=\sum_{k=1}^{m}\sum_{j=1}^{\infty}\frac{\sum_{i=1}^{n}[v_i=k]}{i}x^{kj}\end{aligned}\]

\(b_k\) 為體積為 \(k\) 的物品數量,並且我們只需要次數小於等於 \(m\) 的項,有 \(\ln F\equiv \sum_{k=1}^{m}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\frac{b_k}{i}x^{kj}\pmod{x^{m+1}}\)

右邊可以在 \(\sum_{i=1}^{m}\frac{m}{i}=O(m\ln m)\) 的時間內得到,左邊使用多項式 \(\mathrm{Exp}\)\(O(m\log m)\) 的時間內得到,總時間復雜度 \(O(m\log m)\)

#include <cstdio>
#include <cstring>
#include <algorithm>

typedef long long LL;
const int Mod = 998244353;
const int G = 3, iG = 332748118;
const int MS = 1 << 19 | 7;

inline LL qPow(LL b, int e) {
    LL a = 1;
    for (; e; e >>= 1, b = b * b % Mod)
        if (e & 1) a = a * b % Mod;
    return a;
}

LL Inv[MS];

inline void Init(int N) {
    Inv[1] = 1;
    for (int i = 2; i < N; ++i) Inv[i] = -(Mod / i) * Inv[Mod % i] % Mod;
}

int Sz, R[MS]; LL InvSz;

inline void InitFNTT(int N) {
    int Bt = 0;
    for (; 1 << Bt < N; ++Bt) ;
    if (Sz == (1 << Bt)) return ;
    Sz = 1 << Bt; InvSz = -(Mod - 1) / Sz;
    for (int i = 1; i < Sz; ++i) R[i] = R[i >> 1] >> 1 | (i & 1) << (Bt - 1);
}

inline void FNTT(LL *A, int Ty) {
    for (int i = 0; i < Sz; ++i) if (R[i] < i) std::swap(A[R[i]], A[i]);
    for (int j = 1, j2 = 2; j < Sz; j <<= 1, j2 <<= 1) {
        LL gn = qPow(~Ty ? G : iG, (Mod - 1) / j2), g, X, Y;
        for (int i = 0, k; i < Sz; i += j2) {
            for (k = 0, g = 1; k < j; ++k, g = g * gn % Mod) {
                X = A[i + k], Y = g * A[i + j + k] % Mod;
                A[i + k] = (X + Y) % Mod, A[i + j + k] = (X - Y) % Mod;
            }
        }
    }
    if (!~Ty) for (int i = 0; i < Sz; ++i) A[i] = A[i] * InvSz % Mod;
}

inline void PolyInv(LL *A, int N, LL *B) {
    static LL tA[MS], tB[MS];
    B[0] = qPow(A[0], Mod - 2);
    for (int L = 1; L < N; L <<= 1) {
        int L2 = L << 1, L4 = L << 2;
        InitFNTT(L4);
        memcpy(tA, A, 8 * L2);
        memset(tA + L2, 0, 8 * (Sz - L2));
        memcpy(tB, B, 8 * L);
        memset(tB + L, 0, 8 * (Sz - L));
        FNTT(tA, 1), FNTT(tB, 1);
        for (int i = 0; i < Sz; ++i) tB[i] = (2 - tB[i] * tA[i]) % Mod * tB[i] % Mod;
        FNTT(tB, -1);
        for (int i = 0; i < L2; ++i) B[i] = tB[i];
    }
}

inline void PolyLn(LL *A, int N, LL *B) {
    static LL tA[MS], tB[MS];
    PolyInv(A, N - 1, tB);
    InitFNTT(N * 2 - 3);
    for (int i = 1; i < N; ++i) tA[i - 1] = i * A[i] % Mod;
    memset(tA + N - 1, 0, 8 * (Sz - N + 1));
    memset(tB + N - 1, 0, 8 * (Sz - N + 1));
    FNTT(tA, 1), FNTT(tB, 1);
    for (int i = 0; i < Sz; ++i) tA[i] = tA[i] * tB[i] % Mod;
    FNTT(tA, -1);
    B[0] = 0;
    for (int i = 1; i < N; ++i) B[i] = tA[i - 1] * Inv[i] % Mod;
}

inline void PolyExp(LL *A, int N, LL *B) {
    static LL tA[MS], tB[MS];
    B[0] = 1;
    for (int L = 1; L < N; L <<= 1) {
        int L2 = L << 1, L4 = L << 2;
        memset(B + L, 0, 8 * (L2 - L));
        PolyLn(B, L2, tB);
        InitFNTT(L4);
        memcpy(tA, B, 8 * L);
        memset(tA + L, 0, 8 * (Sz - L));
        for (int i = 0; i < L2; ++i) tB[i] = ((!i) - tB[i] + A[i]) % Mod;
        memset(tB + L2, 0, 8 * (Sz - L2));
        FNTT(tA, 1), FNTT(tB, 1);
        for (int i = 0; i < Sz; ++i) tA[i] = tA[i] * tB[i] % Mod;
        FNTT(tA, -1);
        for (int i = 0; i < L2; ++i) B[i] = tA[i];
    }
}

int N, M;
int buk[MS];
LL A[MS], B[MS];

int main() {
    scanf("%d%d", &N, &M);
    Init(MS);
    for (int i = 1, v; i <= N; ++i) scanf("%d", &v), ++buk[v];
    for (int i = 1; i <= M; ++i) if (buk[i]) {
        for (int j = 1; j <= M / i; ++j) {
            A[i * j] = (A[i * j] + buk[i] * Inv[j]) % Mod;
        }
    }
    PolyExp(A, M + 1, B);
    for (int i = 1; i <= M; ++i) printf("%lld\n", (B[i] + Mod) % Mod);
    return 0;
}

洛谷 P4389: 付公主的背包