[poly] 付公主的背包
每个体积为 \(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;
}

浙公网安备 33010602011771号