[生成函数] 洛谷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;
}
posted @ 2020-11-04 20:10  WR_Eternity  阅读(94)  评论(0编辑  收藏  举报