• [生成函数] 洛谷P4389 付公主的背包


    大体思路

    考虑生成函数

    每一个物品的生成函数:

    (egin{aligned}A(x)=sum_{i=0}x^{iv}=frac{1}{1-x^v}end{aligned})

    (后面为其封闭形式)

    答案:

    (egin{aligned}zeta(x)=prod_{i=1}^nsum_{j=0}x^{v_i imes j}end{aligned})

    时间复杂度 (Theta(nmlog m)),会 (TLE)

    把每一个物品的生成函数都卷起来时间复杂度吃不消——但是加起来是可以的。

    考虑给(A(x))取个(ln),然后再(exp)回去。

    设:

    (F(x)=1-x^v,G(x)=ln F(x))

    开始推式子:

    (egin{aligned} G(x)&=ln F(x)\ G'(x)&=frac{F'(x)}{F(x)}\ G'(x)&=-frac{v imes x^{v-1}}{1-x^v}\ G'(x)&=-sum_{i=0}v imes x^{v-1} imes x^{iv}\ G'(x)&=-sum_{i=0}v imes x^{iv+v-1}\ G(x)&=-sum_{i=0}frac{v imes x^{v(i+1)}}{v imes(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
    ",b[i]);
    	return 0;
    }
    
  • 相关阅读:
    安装触动精灵
    云集微助手安装教程和授权说明old
    造粉神器下载地址
    兵工厂安装和使用教程
    云集微助手-操作简介
    转:二叉树的深度优先遍历和广度优先遍历
    转:背包问题的解法
    Moco搭建测试服务器
    Jmeter的内嵌函数和变量
    Jmeter输出HTML的性能测试报告
  • 原文地址:https://www.cnblogs.com/WR-Eternity/p/13927941.html
Copyright © 2020-2023  润新知