Loading [MathJax]/jax/output/CommonHTML/jax.js

【Luogu P4389】付公主的背包

Problem#

Description#

给出 n 种物品,每种物品体积为 vi ,件数可视作无限。给定 m ,求出用这些商品装满容积分别为 1m 的这 m 个背包的方案数。

Input Format#

第一行两个正整数 n,m

接下来一行 n 个数,每个数 vi 表示第 i 种物品的体积。

Output Format#

mm 个整数,第 i 行表示对于体积为 i 的背包有多少种方案,答案对 998244353 取模。

Range#

n,m105,vim

Algorithm#

多项式,生成函数

Mentality#

对于一种体积为 vi 的物品,它的生成函数为:

fi(x)=k=1xvik

可以得到封闭表达式:fi(x)=11xvi

显然有答案的生成函数 Ans=ni=1fi(x)

当然我们并不能把所有的函数乘起来,转而考虑一下利用 ln 转化成加法。

ln(fi(x))=ln(11xvi)=(1xvi)fi(x)=(1xvi)vikxvik1=vixvik1

这个时候我们再积分回去就得到了:

ln(fi(x))=1kxvik

由于物品体积总数就那么一点,我们直接把相同体积的物品一起加到 Ans 的对应位置去就好了。

不难看出这部分复杂度为 nln(n)

然后再把 Ansexp 回去就好了。

Code#

Copy
#include <cmath> #include <cstdio> #include <iostream> using namespace std; #define LL long long #define inline __inline__ __attribute__((always_inline)) inline LL read() { LL x = 0, w = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } return x * w; } const int Max_n = 6e5 + 5, mod = 998244353, G = 3, Len = 1 << 19; int ksm(int a, int b = mod - 2) { int res = 1; for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod; return res; } namespace Poly { int bit, len, rev[Max_n]; int gp[Max_n], invn[Max_n]; struct poly { int f[Max_n]; inline int& operator[](int x) { return f[x]; } void Init() { for (int i = 0; i < Max_n; i++) f[i] = 0; } void dft(int t) { for (int i = 0; i < len; i++) if (rev[i] > i) swap(f[i], f[rev[i]]); for (int l = 1; l < len; l <<= 1) { int Wn = Len / (l << 1); for (int i = 0; i < len; i += l << 1) { for (int k = i; k < i + l; k++) { int x = f[k], p = (k - i) * Wn; int y = 1ll * f[k + l] * (t == -1 ? gp[Len - p] : gp[p]) % mod; f[k] = (x + y) % mod, f[k + l] = (x - y + mod) % mod; } } } if (t == -1) for (int i = 0, Inv = ksm(len); i < len; i++) f[i] = 1ll * f[i] * Inv % mod; } }; void init(int n) { len = 1 << (bit = log2(n) + 1); for (int i = 0; i < len; i++) rev[i] = rev[i >> 1] >> 1 | ((i & 1) << bit - 1); } void inv(int n, poly &f, poly &g) { static poly F; F.Init(), g.Init(); g[0] = ksm(f[0]); for (int deg = 2; deg < (n << 1); deg <<= 1) { init(deg * 3); for (int i = 0; i < deg; i++) F[i] = f[i]; for (int i = deg; i < len; i++) F[i] = 0; g.dft(1), F.dft(1); for (int i = 0; i < len; i++) g[i] = 1ll * g[i] * (2 - 1ll * g[i] * F[i] % mod + mod) % mod; g.dft(-1); for (int i = deg; i < len; i++) g[i] = 0; } } void ln(int n, poly &f, poly &g) { static poly df, Inv; df.Init(); for (int i = 0; i < n - 1; i++) df[i] = 1ll * f[i + 1] * (i + 1) % mod; inv(n, f, Inv), g.Init(), init(n * 2); df.dft(1), Inv.dft(1); for (int i = 0; i < len; i++) g[i] = 1ll * df[i] * Inv[i] % mod; g.dft(-1); for (int i = n - 1; i; i--) g[i] = 1ll * g[i - 1] * invn[i] % mod; g[0] = 0; } void exp(int n, poly &f, poly &g) { static poly Ln, F; g.Init(), F.Init(); g[0] = 1; for (int deg = 2; deg < (n << 1); deg <<= 1) { ln(deg, g, Ln), init(deg); for (int i = 0; i < deg; i++) F[i] = f[i]; for (int i = deg; i < len; i++) F[i] = 0; g.dft(1), F.dft(1), Ln.dft(1); for (int i = 0; i < len; i++) g[i] = 1ll * g[i] * (1 - Ln[i] + F[i] + mod) % mod; g.dft(-1); for (int i = deg; i < len; i++) g[i] = 0; } } } using namespace Poly; int n, m, exi[Max_n]; poly a, ans; namespace Input { void main() { n = read(), m = read(); for (int i = 0; i < n; i++) exi[read()]++; } } // namespace Input namespace Init { void main() { for (int i = 1; i <= n; i++) if (exi[i]) for (int j = 1; j * i <= m; j++) (a[j * i] += 1ll * exi[i] * ksm(j) % mod) %= mod; invn[0] = invn[1] = gp[0] = 1; int g = ksm(G, (mod - 1) / Len); for (int i = 1; i <= Len; i++) gp[i] = 1ll * gp[i - 1] * g % mod; for (int i = 2; i < Len; i++) invn[i] = 1ll * (mod - mod / i) * invn[mod % i] % mod; } } // namespace Init namespace Solve { void main() { exp(m + 1, a, ans); for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); } } // namespace Solve int main() { #ifndef ONLINE_JUDGE freopen("4389.in", "r", stdin); freopen("4389.out", "w", stdout); #endif Input::main(); Init::main(); Solve::main(); }
posted @   洛水·锦依卫  阅读(193)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示

目录

目录

×