付公主有一个可爱的背包qwq
这个背包最多可以装 (10^5) 大小的东西
付公主有 (n) 种商品,她要准备出摊了
每种商品体积为 (v_i),都有无限件
给定 (m),对于 (sin [1,m]),请你回答用这些商品恰好装 (s) 体积的方案数
考虑对每个物品写出OGF,以体积作为(x)的次数
[F_i(x)=sum_{jge0}x^{jv_i}=frac{1}{1-x^{v_i}}
]
那么最后的答案为
[G(x)=prod_{i=1}^nF_i(x)=prod_{i=1}^nfrac{1}{1-x^{v_i}}
]
而这个东西是不好求的,因为有(prod),而我们擅长求(sum),所以我们可以先用ln把这个变为加法,再exp回去
[egin{aligned}
explnG(x)&=expsum_{i=1}^nlnfrac{1}{1-x^{v_i}}\
&=expsum_{i=1}^nsum_{jge1}frac{x^{jv_i}}{j}\
end{aligned}]
我们可以把体积相同的物品合成一个,假设体积为(i)的物品有(b_i)个,于是得到
[expsum_{kge1}b_ksum_{jge1}^{jkle m}frac{x^{jk}}{j}
]
而我们知道对于给定的(m),只有前(m)项是有用的,所以(jkle m),于是这么直接枚举(k)和(j)的复杂度是(O(mlogm))的,最后再exp回去即可
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 4e5;
const int p = 998244353;
using namespace std;
int n,m,v[N + 5],b[N + 5],a[N + 5],maxn,lg,rev[N + 5],G[N + 5][2],ans[N + 5];
int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
void pre(int n)
{
maxn = 1,lg = 0;
while (maxn <= n)
maxn <<= 1,lg++;
for (int i = 0;i < maxn;i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
}
void clear(int *a,int n,int l = 0)
{
for (int i = l;i < n;i++)
a[i] = 0;
}
void ntt(int *a,int typ)
{
for (int i = 0;i < maxn;i++)
if (i < rev[i])
swap(a[i],a[rev[i]]);
for (int i = 1;i < maxn;i <<= 1)
for (int j = 0;j < maxn;j += i << 1)
for (int k = 0;k < i;k++)
{
int x = a[j + k],t = 1ll * G[k + i][typ] * a[j + k + i] % p;
a[j + k] = (x + t) % p;
a[j + k + i] = (x - t) % p;
}
if (!typ)
{
int inv = mypow(maxn,p - 2);
for (int i = 0;i < maxn;i++)
a[i] = 1ll * a[i] * inv % p;
}
}
int INVa[N + 5];
void INV(int *a,int *ans,int n)
{
if (n == 1)
{
ans[0] = mypow(a[0],p - 2);
return;
}
INV(a,ans,n + 1 >> 1);
pre(n * 2);
for (int i = 0;i < n;i++)
INVa[i] = a[i];
clear(INVa,maxn,n);
ntt(INVa,1);
ntt(ans,1);
for (int i = 0;i < maxn;i++)
ans[i] = (2ll * ans[i] % p - 1ll * INVa[i] * ans[i] % p * ans[i] % p) % p;
ntt(ans,0);
clear(ans,maxn,n);
}
int Lna[N + 5],Lnb[N + 5];
void DOV(int *a,int *f,int n)
{
for (int i = 1;i < n;i++)
f[i - 1] = 1ll * i * a[i] % p;
f[n - 1] = 0;
}
void DOVINV(int *a,int *f,int n)
{
f[0] = 0;
for (int i = 1;i < n;i++)
f[i] = 1ll * mypow(i,p - 2) * a[i - 1] % p;
}
void Ln(int *a,int *ans,int n)
{
DOV(a,Lna,n);
pre(n * 2);
clear(Lnb,maxn);
INV(a,Lnb,n);
pre(n * 2);
clear(Lna,maxn,n);
ntt(Lna,1);
ntt(Lnb,1);
for (int i = 0;i < maxn;i++)
Lna[i] = 1ll * Lna[i] * Lnb[i] % p;
ntt(Lna,0);
DOVINV(Lna,ans,n);
clear(ans,maxn,n);
}
int expa[N + 5],expb[N + 5];
void exp(int *a,int *ans,int n)
{
if (n == 1)
{
ans[0] = 1;
return;
}
exp(a,ans,n + 1 >> 1);
Ln(ans,expa,n);
pre(n * 2);
for (int i = 0;i < n;i++)
expb[i] = a[i];
clear(expb,maxn,n);
ntt(ans,1);
ntt(expa,1);
ntt(expb,1);
for (int i = 0;i < maxn;i++)
ans[i] = 1ll * ans[i] * ((1 - expa[i] + expb[i]) % p) % p;
ntt(ans,0);
clear(ans,maxn,n);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;i++)
scanf("%d",&v[i]),b[v[i]]++;
pre(m * 2 + 2);
for (int i = 1;i < maxn;i <<= 1)
{
int g1 = mypow(3,(p - 1) / (i << 1)),g2 = mypow(mypow(3,p - 2),(p - 1) / (i << 1));
G[i][0] = G[i][1] = 1;
for (int j = 1;j < i;j++)
G[i + j][1] = 1ll * G[i + j - 1][1] * g1 % p,G[i + j][0] = 1ll * G[i + j - 1][0] * g2 % p;
}
for (int k = 1;k <= m;k++)
if (b[k])
for (int j = 1;j * k <= m;j++)
a[j * k] += 1ll * b[k] * mypow(j,p - 2) % p,a[j * k] %= p;
exp(a,ans,m + 1);
for (int i = 1;i <= m;i++)
printf("%d
",(ans[i] + p) % p);
return 0;
}