付公主的背包
P4389 付公主的背包
对于一种商品,设其\(OGF\)为\(f_i(x) = \sum x^{v_ij} = \frac{1}{1 - x^{v_i}}\)。
那么答案就为\(\prod f_i(x)\),套路的,求 \(\ln\),则原式为
\[\sum \ln f_i(x) = -\sum \ln (1 - x^{v_i})
\]
其中
\[\ln (1 - x^{v_i}) = -\sum_{j \ge 1} \frac{x^{v_ij}}{j}
\]
所以答案就为
\[\exp (\sum_i \sum_{j\ge1}\frac{x^{v_ij}}{j})
\]
发现\(v_ij \le m\),直接枚举,时间复杂度\(o(m \ln m)\)
总时间为\(O(n \log n)\).
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#define IN inline
#define LL long long
using namespace std;
const int N = 2e5 + 5, P = 998244353, G = 3;
int n, m, a[N << 2], b[N << 2];
IN int read() {
int t = 0,res = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) t |= (ch == '-');
for (; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ 48);
return t ? -res : res;
}
LL fpow(LL x, LL y) {
LL res = 1;
for (; x; x >>= 1, y = y * y % P)
if (x & 1) res = res * y % P;
return res;
}
const int invG = fpow(P - 2, G);
namespace Poly{
int rev[N << 2], insF[N << 2], sginv[N << 2];
void NTT(int *f, int len, int fl) {
static int W[N << 2] = {1};
if (len == 1) return;
for (int i = 0; i < len; i++)
if (i < rev[i]) swap(f[i], f[rev[i]]);
for (int l = 1; l < len; l <<= 1) {
int I = fpow((P - 1) / (l << 1), fl == 1 ? G : invG);
for (int i = 1; i < l; i++) W[i] = (LL)W[i - 1] * I % P;
for (int i = 0; i < len; i += (l << 1))
for (int j = 0; j < l; j++) {
int x = f[i | j], y = (LL)f[i | j | l] * W[j] % P;
f[i | j] = (x + y >= P ? x + y - P : x + y);
f[i | j | l] = (x - y < 0 ? x - y + P : x - y);
}
}
if (fl == -1) {
int IV = fpow(P - 2, len);
for (int i = 0; i < len; i++) f[i] = (LL)f[i] * IV % P;
}
}
void Mulpoly(int *f, int *g, int lenF, int lenG) {
int len = 1, bit = 0;
while (len <= lenF + lenG) len <<= 1, bit++;
for (int i = 1; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
NTT(f, len, 1), NTT(g, len, 1);
for (int i = 0; i < len; i++) f[i] = (LL)f[i] * g[i] % P;
NTT(f, len, -1);
for (int i = lenF + lenG + 1; i < len; i++) f[i] = 0;
}
void Invpoly(int *f, int lenF, int *g) { // [0, lenF);
static int s2[N << 2], s1[N << 2];
int limit = 1; while (limit < lenF) limit <<= 1;
g[0] = fpow(P - 2, f[0]);
for (int len = 2, bit = 1; len <= limit; len <<= 1, bit++) {
for (int i = 1; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
for (int i = 0; i < (len >> 1); i++) s2[i] = g[i];
for (int i = (len >> 1); i < len; i++) s2[i] = 0;
for (int i = 0; i < len; i++) s1[i] = f[i];
NTT(s2, len, 1), NTT(s1, len, 1);
for (int i = 0; i < len; i++) s1[i] = (LL)s2[i] * s1[i] % P;
NTT(s1, len, -1);
for (int i = 0; i < (len >> 1); i++) s1[i] = 0;
NTT(s1, len, 1);
for (int i = 0; i < len; i++) s1[i] = (LL)s1[i] * s2[i] % P;
NTT(s1, len, -1);
for (int i = (len >> 1); i < len; i++) g[i] = (s1[i] == 0 ? 0 : P - s1[i]);
}
for (int i = lenF; i < limit; i++) g[i] = 0;
for (int i = 0; i < limit; i++) s2[i] = s1[i] = 0;
}
void Getsginv(int len) {
sginv[0] = sginv[1] = 1;
for (int i = 2; i <= len; i++) sginv[i] = (LL)sginv[P % i] * (P - P / i) % P;
}
void Dpoly(int *f, int lenF) {
for (int i = 0; i < lenF; i++) f[i] = (LL)f[i + 1] * (i + 1) % P;
f[lenF] = 0;
}
void Jfpoly(int *f, int lenF) {
for (int i = lenF; i >= 0; i--) f[i + 1] = (LL)f[i] * sginv[i + 1] % P;
f[0] = 0;
}
void Lnpoly(int *f, int lenF) { // [0, lenF)
static int Inv_f[N << 2];
Invpoly(f, lenF, Inv_f), Dpoly(f, lenF - 1), Mulpoly(f, Inv_f, lenF - 1, lenF - 1), Jfpoly(f, lenF - 1);
for (int i = lenF; i <= (lenF << 1); i++) f[i] = Inv_f[i] = 0;
for (int i = 0; i < lenF; i++) Inv_f[i] = 0;
}
void Exppoly(int *f, int lenF, int *g) {
static int s[N << 2];
int limit = 1; while (limit < lenF) limit <<= 1;
g[0] = 1;
for (int len = 2; len <= limit; len <<= 1) {
for (int i = (len >> 1); i < len; i++) g[i] = 0;
for (int i = 0; i < (len >> 1); i++) s[i] = g[i];
for (int i = (len >> 1); i < len; i++) s[i] = 0;
Lnpoly(s, len);
for (int i = 0; i < len; i++) s[i] = (f[i] - s[i] + P) % P;
s[0] = (s[0] + 1) % P, Mulpoly(g, s, len - 1, len - 1);
}
for (int i = lenF; i < limit; i++) g[i] = 0;
for (int i = 0; i < limit; i++) s[i] = 0;
}
}
void write(int x) {
if (!x) return; write(x / 10), putchar((x % 10) + '0');
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) a[read()]++;
Poly::Getsginv(m << 2);
for (int i = 1; i <= m; i++)
for (int j = i, k = 1; j <= m; j += i, k++)
(b[j] += (LL)a[i] * Poly::sginv[k] % P) %= P;
memset(a, 0, sizeof a);
Poly::Exppoly(b, m + 1, a);
for (int i = 1; i <= m; i++)
if (!a[i]) puts("0");
else write(a[i]), puts("");
}