[生成函数] 洛谷P4389 付公主的背包
大体思路
考虑生成函数
每一个物品的生成函数:
\(\begin{aligned}A(x)=\sum_{i=0}x^{iv}=\frac{1}{1-x^v}\end{aligned}\)
(后面为其封闭形式)
答案:
\(\begin{aligned}\zeta(x)=\prod_{i=1}^n\sum_{j=0}x^{v_i\times j}\end{aligned}\)
时间复杂度 \(\Theta(nm\log m)\),会 \(TLE\)。
把每一个物品的生成函数都卷起来时间复杂度吃不消——但是加起来是可以的。
考虑给\(A(x)\)取个\(\ln\),然后再\(exp\)回去。
设:
\(F(x)=1-x^v,G(x)=\ln F(x)\)
开始推式子:
\(\begin{aligned} G(x)&=\ln F(x)\\ G'(x)&=\frac{F'(x)}{F(x)}\\ G'(x)&=-\frac{v\times x^{v-1}}{1-x^v}\\ G'(x)&=-\sum_{i=0}v\times x^{v-1}\times x^{iv}\\ G'(x)&=-\sum_{i=0}v\times x^{iv+v-1}\\ G(x)&=-\sum_{i=0}\frac{v\times x^{v(i+1)}}{v\times(i+1)}\\ G(x)&=-\sum_{i=1}\frac{x^{iv}}{i}\\ \ln A(x)&=\sum_{i=1}\frac{x^{iv}}{i} \end{aligned}\)
有了这个式子,我们就可以很容易地将各物品的\(\ln\)的和求出来了,然后再将求出来的式子进行\(exp\)还原即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5,mod=998244353;
int a[N],b[N],rev[N],inv[N],cnt[N],n,m,L,x;
int pow(int a,int b){
int res=1,c=a;
while (b){
if (b&1) res=1ll*res*c%mod;
b>>=1,c=1ll*c*c%mod;
}
return res;
}
void Get(int n,int opt=1){
L=opt?1:n;
while (L<n) L<<=1;
for (int i=1;i<L;i++) rev[i]=rev[i>>1]>>1|((i&1)?L>>1:0);
}
void fft(int *a,int opt){
for (int i=0;i<L;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int l=2;l<=L;l<<=1){
int W=opt==1?pow(3,(mod-1)/l):pow(pow(3,(mod-1)/l),mod-2);
for (int i=0;i<L;i+=l)
for (int j=0,w=1;j<l>>1;j++,w=1ll*w*W%mod){
int x=a[i+j],y=1ll*a[i+j+l/2]*w%mod;
a[i+j]=(x+y)%mod,a[i+j+l/2]=(x-y)%mod;
}
}
if (opt==-1) for (int i=0,v=pow(L,mod-2);i<L;i++) a[i]=1ll*a[i]*v%mod;
}
void Qiud(int *f,int *g,int n){
f[n-1]=0;
for (int i=0;i<n-1;i++) f[i]=1ll*g[i+1]*(i+1)%mod;
}
void Jif(int *f,int *g,int n){
f[0]=0;
for (int i=1;i<n;i++) f[i]=1ll*g[i-1]*inv[i]%mod;
}
void Inv(int *f,int *g,int n){
int c[N];
f[0]=pow(g[0],mod-2);
for (int l=2;l<n<<1;l<<=1){
Get(l<<1,0);
for (int i=0;i<l;i++) c[i]=g[i];
for (int i=l;i<L;i++) c[i]=0;
fft(f,1),fft(c,1);
for (int i=0;i<L;i++) f[i]=(2-1ll*c[i]*f[i])%mod*f[i]%mod;
fft(f,-1);
for (int i=l;i<L;++i) f[i]=0;
}
}
void Ln(int *f,int *g,int n){
int c[N],d[N];
for (int i=0;i<n;i++) c[i]=d[i]=0;
Inv(c,g,n),Qiud(d,g,n);
Get(n<<1);
for (int i=n;i<L;i++) c[i]=d[i]=0;
fft(c,1),fft(d,1);
for (int i=0;i<L;i++) d[i]=1ll*c[i]*d[i]%mod;
fft(d,-1);
Jif(f,d,n);
}
void Exp(int *f,int *g,int n){
int c[N],d[N];
f[0]=1;
for (int l=2;l<n<<1;l<<=1){
Ln(d,f,l);
Get(l<<1,0);
for (int i=0;i<l;i++) c[i]=g[i];
for (int i=l;i<L;i++) c[i]=d[i]=0;
fft(f,1),fft(c,1),fft(d,1);
for (int i=0;i<L;i++) f[i]=(1ll-d[i]+c[i])*f[i]%mod;
fft(f,-1);
}
}
int main(){
inv[1]=1;
for (int i=2;i<=400000;i++) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++) scanf("%d",&x),++cnt[x];
for (int i=1;i<=m;i++)
if (cnt[i]){
for (int j=1;i*j<=m;j++)
a[i*j]=(1ll*a[i*j]+1ll*cnt[i]*inv[j]%mod)%mod;
}
Exp(b,a,m+1);
for (int i=1;i<=m;i++) b[i]=(b[i]+mod)%mod,printf("%d\n",b[i]);
return 0;
}