付公主的背包 题解
Problem:
有\(n\)种物品,每种物品体积为\(v_i\),数量无限,给定\(m\),求$ \forall s \in [1,m]\(,恰好装\)s$体积的方案数,\(1 \leq n,m \leq 10^5\)
Solution
考虑每一种物品的生成函数\(G_i(x)=\sum\limits_{i=0}^{\infty}x^{iv_i}=\frac{1}{1-x^{v_i}}\)
那么总方案的生成函数就为\(F(x)=\prod\limits_{i=1}^n\frac{1}{1-x^{v_i}}\)
感觉\(\prod\)并不好怎么转化,直接处理肯定过不了,考虑把\(\prod\)化为\(\sum\)
两边取\(ln\),得\(lnF(x)=-\sum\limits_{i=1}^nln(1-x^{v_i})\)
发现现在我们好像仍然没有什么好办法......那么开始推式子都试一遍
考虑等式右边形如\(ln(1-x^k)\)的这个函数,令其为\(H(x)\)
我们有\(H(x)'=-kx^{k-1}\frac{1}{1-x^{k}}\)
幂级数展开:\(H(x)'=-kx^{k-1}\sum\limits_{i=0}^{\infty}x^{ki}=\sum\limits_{i=0}^{\infty}-kx^{ki+k-1}=\sum\limits_{i=1}^{\infty}-kx^{ki-1}\)
逐项积分:\(H(x)=\sum\limits_{i=1}^{\infty}-\frac{x^{ki}}{i}\)
??好像这个式子有点用挺好看的
那么\(lnF(x)=\sum\limits_{i=1}^n\sum\limits_{j=1}^{m/v_i}\frac{x^{v_ij}}{j}=\sum\limits_{v=1}^{Max}\sum\limits_{i=1}^{m/v}cnt_v\frac{x^{vi}}{i}\)
算这个式子的复杂度是可以接受的
那么最后再多项式exp回去即可,总复杂度\(O(mlogm)\)
Code
#include<bits/stdc++.h>
#define PR 3
#define mod 998244353
#define LL long long
using namespace std;
int n,m,rev[400005];
LL F[400005],G[400005],H[400005],P[400005],R[400005],inv[400005],bar[400005];
inline char Getchar(){
static char s[1<<16],*S,*T;
return (S==T)&&(T=(S=s)+fread(s,1,1<<16,stdin),S==T)?EOF:*S++;
}
inline int read(){
int x=0,f=1;char ch=Getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=Getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=Getchar();
}
return x*f;
}
inline LL quick_power(LL x,int k){
LL res=1;
while(k){
if(k&1)
res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
namespace Polynomial{
void Derivative(LL *F,int Lim){
for(register int i=0;i<Lim-1;++i)
F[i]=F[i+1]*(i+1)%mod;
F[Lim-1]=0;return;
}
void Integral(LL *F,int Lim){
for(register int i=Lim;i;--i)
F[i]=F[i-1]*inv[i]%mod;
F[0]=0;return;
}
void NTT(LL *F,int Lim,int op){
for(register int i=0;i<Lim;++i){
if(i<rev[i])
swap(F[i],F[rev[i]]);
}
for(register int mid=1;mid<Lim;mid<<=1){
int R=mid<<1;
LL rt=quick_power(PR,(mod-1)/R);
for(register int j=0;j<Lim;j+=R){
LL w=1;
for(register int k=0;k<mid;++k){
LL x=F[j|k],y=w*F[j|k|mid]%mod;
F[j|k]=(x+y)%mod;
F[j|k|mid]=(x-y+mod)%mod;
w=w*rt%mod;
}
}
}
if(op==-1){
reverse(F+1,F+Lim);
LL Inv=quick_power(Lim,mod-2);
for(register int i=0;i<Lim;++i)
F[i]=F[i]*Inv%mod;
}
return;
}
void Polyinv(int N,LL *F,LL *G){
if(N==1){
G[0]=quick_power(F[0],mod-2);
return;
}
Polyinv(N+1>>1,F,G);
int Lim=1,Len=-1;
while(Lim<(N<<1))
Lim<<=1,++Len;
for(register int i=0;i<Lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
for(register int i=0;i<Lim;++i)
H[i]=i<N?F[i]:0;
NTT(H,Lim,+1);NTT(G,Lim,+1);
for(register int i=0;i<Lim;++i)
G[i]=G[i]*(2-G[i]*H[i]%mod+mod)%mod;
NTT(G,Lim,-1);
for(register int i=N;i<Lim;++i)
G[i]=0;
return;
}
void Polyln(int N,LL *F,LL *G){
Polyinv(N,F,G);
Derivative(F,N);
int Lim=1,Len=-1;
while(Lim<(N<<1))
Lim<<=1,++Len;
for(register int i=0;i<Lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
NTT(F,Lim,+1);NTT(G,Lim,+1);
for(register int i=0;i<Lim;++i)
G[i]=F[i]*G[i]%mod;
NTT(G,Lim,-1);
Integral(G,N);
return;
}
void Polyexp(int N,LL *F,LL *G){
if(N==1){
G[0]=1;
return;
}
Polyexp(N+1>>1,F,G);
for(register int i=0;i<(N+1>>1);++i)
R[i]=G[i],P[i]=0;
Polyln(N,R,P);
P[0]=F[0]-P[0]+1;
for(register int i=1;i<(N<<1);++i)
P[i]=i<N?(F[i]-P[i]+mod)%mod:0;
int Lim=1,Len=-1;
while(Lim<(N<<1))
Lim<<=1,++Len;
for(register int i=0;i<Lim;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<Len);
NTT(G,Lim,+1);NTT(P,Lim,+1);
for(register int i=0;i<Lim;++i)
G[i]=G[i]*P[i]%mod;
NTT(G,Lim,-1);
for(register int i=N;i<Lim;++i)
G[i]=P[i]=R[i]=0;
return;
}
}using namespace Polynomial;
int main(){
n=read();m=read()+1;
inv[1]=1;
for(register int i=2;i<=m;++i)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(register int i=1;i<=n;++i)
++bar[read()];
for(register int i=1;i<=m;++i){
if(!bar[i])
continue;
for(register int j=1;i*j<=m;++j)
F[i*j]=(F[i*j]+bar[i]*inv[j]%mod)%mod;
}
Polyexp(m,F,G);
for(register int i=1;i<m;++i)
printf("%lld\n",G[i]);
return 0;
}