洛谷传送门
题目描述
这个背包最多可以装 1 0 5 10^5 105大小的东西
付公主有 n n n种商品,她要准备出摊了
每种商品体积为 V i V_i Vi,都有 1 0 5 10^5 105件
给定 m m m,对于 s ∈ [ 1 , m ] s\in [1,m] s∈[1,m],请你回答用这些商品恰好装 s s s体积的方案数
输入输出格式
输入格式:
第一行 n , m n,m n,m
第二行 V 1 ∼ V n V_1\sim V_n V1∼Vn
输出格式:
m m m行,第 i i i行代表 s = i s=i s=i时方案数,对 998244353 998244353 998244353取模
输入输出样例
输入样例#1:
2 4
1 2
输出样例#1:
1
2
2
3
说明
对于30%的数据, n ≤ 3000 , m ≤ 3000 n\le 3000,m\le 3000 n≤3000,m≤3000
对于60%的数据,纯随机生成
对于100%的数据, n ≤ 100000 , m ≤ 100000 n\le 100000,m\le 100000 n≤100000,m≤100000
对于100%的数据, V i ≤ m V_i\le m Vi≤m
解题分析
对于一个体积为 V i V_i Vi的物品, 其生成函数为 1 + x V i + x 2 V i + . . . + x k V i = 1 1 − x V i 1+x^{V_i}+x^{2V_i}+...+x^{kVi}=\frac{1}{1-x^{V_i}} 1+xVi+x2Vi+...+xkVi=1−xVi1。那么很显然我们就是要快速求所有生成函数的积, 找到对应项的系数即可。
关键是如何快速求这个玩意。 有个很套路的做法是先把这玩意求 l n ln ln加上再 e x p exp exp回去。
那么开始推式子: 设
f
(
x
)
f(x)
f(x)为第
i
i
i个物品的生成函数,
g
(
x
)
=
l
n
(
f
(
x
)
)
g(x)=ln(f(x))
g(x)=ln(f(x)), 那么有:
g
′
(
x
)
=
f
′
(
x
)
f
(
x
)
=
∑
k
≥
1
k
V
i
x
k
V
i
−
1
1
1
−
x
V
i
=
(
1
−
x
V
i
)
∑
k
≥
1
k
V
i
x
k
V
i
−
1
=
∑
k
≥
1
V
i
x
k
V
i
−
1
g
(
x
)
=
∑
k
≥
1
1
k
x
k
V
i
g'(x)=\frac{f'(x)}{f(x)} \\ =\frac{\sum_{k\ge 1}kV_ix^{kV_i-1}}{\frac{1}{1-x^{V_i}}} \\ =(1-x^{V_i})\sum_{k\ge 1}kV_ix^{kV_i-1} \\ =\sum_{k\ge 1}V_ix^{kV_i-1} \\ g(x)=\sum_{k\ge 1}\frac{1}{k}x^{kV_i}
g′(x)=f(x)f′(x)=1−xVi1∑k≥1kVixkVi−1=(1−xVi)k≥1∑kVixkVi−1=k≥1∑VixkVi−1g(x)=k≥1∑k1xkVi
所以这玩意记录一下出现次数可以
O
(
N
l
n
(
N
)
)
O(Nln(N))
O(Nln(N))求。
那么剩下的就是一个 e x p exp exp的板子辣!
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cstring>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 600500
#define MOD 998244353
#define g 3
#define ginv 332748118
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
IN int fpow(R int base, R int tim)
{
int ret = 1;
W (tim)
{
if (tim & 1) ret = 1ll * ret * base % MOD;
base = 1ll * base * base % MOD, tim >>= 1;
}
return ret;
}
int a1[MX], a2[MX], b1[MX], b2[MX], b3[MX], b4[MX], c[MX];
int inv[MX], A[MX], rev[MX], res[MX], cnt[MX];
namespace Poly
{
IN void NTT(int *dat, R int len, R bool typ)
{
for (R int i = 1; i < len; ++i) if (rev[i] > i) std::swap(dat[i], dat[rev[i]]);
R int seg, step, bd, now, cur, base, deal, buf1, buf2;
for (seg = 1; seg < len; seg <<= 1)
{
base = fpow(typ ? g : ginv, (MOD - 1) / (seg << 1)), step = seg << 1;
for (now = 0; now < len; now += step)
{
deal = 1, bd = now + seg;
for (cur = now; cur < bd; cur++, deal = 1ll * deal * base % MOD)
{
buf1 = dat[cur], buf2 = 1ll * dat[cur + seg] * deal % MOD;
dat[cur] = (buf1 + buf2) % MOD, dat[cur + seg] = (buf1 - buf2 + MOD) % MOD;
}
}
}
if (typ) return; int inv = fpow(len, MOD - 2);
for (R int i = 0; i < len; ++i) dat[i] = 1ll * inv * dat[i] % MOD;
}
IN void Dr(int *dat, int *dr, R int len) {for (R int i = 1; i < len; ++i) dr[i - 1] = 1ll * dat[i] * i % MOD; dr[len - 1] = 0;}
IN void Itg(int *dat, int *itg, R int len) {for (R int i = 1; i < len; ++i) itg[i] = 1ll * dat[i - 1] * fpow(i, MOD - 2) % MOD; itg[0] = 0;}
IN void Getinv(R int up, R int lg, int *ind, int *ans)
{
if (up == 1) return ans[0] = fpow(ind[0], MOD - 2), void();
Getinv(up >> 1, lg - 1, ind, ans); int len = up << 1, half = up >> 1; lg++;
for (R int i = 0; i < len; ++i) a1[i] = a2[i] = 0;
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < half; ++i) a1[i] = ans[i];
for (R int i = 0; i < up; ++i) a2[i] = ind[i];
NTT(a1, len, 1), NTT(a2, len, 1);
for (R int i = 0; i < len; ++i) a1[i] = (a1[i] * 2 % MOD - 1ll * a1[i] * a1[i] % MOD * a2[i] % MOD + MOD) % MOD;
NTT(a1, len, 0);
for (R int i = 0; i < up; ++i) ans[i] = a1[i];
}
IN void Getln(R int up, R int lg, int *dat, int *ans)
{
Dr(dat, b1, up); Getinv(up, lg, dat, b2);
int len = up << 1; lg++;
for (R int i = 0; i < len; ++i) a1[i] = a2[i] = 0;
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < up; ++i) a1[i] = b1[i], a2[i] = b2[i];
NTT(a1, len, 1), NTT(a2, len, 1);
for (R int i = 0; i < len; ++i) a1[i] = 1ll * a1[i] * a2[i] % MOD;
NTT(a1, len, 0); Itg(a1, ans, up);
}
IN void Getexp(R int up, R int lg)
{
if (up == 1) return res[0] = 1, void();
Getexp(up >> 1, lg - 1); Getln(up, lg, res, c);
int len = up << 1, half = up >> 1; lg++;
for (R int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
for (R int i = 0; i < len; ++i) a1[i] = a2[i] = 0;
for (R int i = 0; i < up; ++i) a1[i] = (A[i] - c[i] + MOD) % MOD;
for (R int i = 0; i < half; ++i) a2[i] = res[i];
a1[0] = (a1[0] + 1) % MOD; NTT(a1, len, 1), NTT(a2, len, 1);
for (R int i = 0; i < len; ++i) a1[i] = 1ll * a1[i] * a2[i] % MOD;
NTT(a1, len, 0);
for (R int i = 0; i < up; ++i) res[i] = a1[i];
}
}
int main(void)
{
int n, m, foo; in(n), in(m); inv[0] = inv[1] = 1;
for (R int i = 2; i <= m; ++i) inv[i] = 1ll * inv[MOD % i] * (MOD - MOD / i) % MOD;
for (R int i = 1; i <= n; ++i) in(foo), ++cnt[foo];
for (R int i = 1; i <= m; ++i)
{
if (cnt[i])
for (R int j = 1; i * j <= m; ++j)
(A[j * i] += 1ll * inv[j] * cnt[i] % MOD) %= MOD;
}
int len = 1, lg = 0;
for (; len <= m; len <<= 1, lg++);
Poly::Getexp(len, lg);
for (R int i = 1; i <= m; ++i) printf("%d\n", res[i]);
}