zoukankan      html  css  js  c++  java
  • 【洛谷4389】付公主的背包(多项式Exp)

    点此看题面

    • (n)种物品和一个大小为(m)的背包。
    • 每种物品都有无限个,其中第(k)种物品体积为(v_k)
    • 对于([1,m])中的每一种体积(i),求出选择物品总体积恰好为(i)的方案数。
    • (n,mle10^5)

    生成函数

    考虑对于第(i)种物品,我们可以得出它的生成函数:

    [F_i(x)=sum_{k=0}^{+infty}x^{k imes v_i}=frac 1{1-x^{v_i}} ]

    一种暴力的做法就是将(n)个生成函数全部卷起来,但这显然直接(T)飞。

    众所周知,有一种很好的把乘法变成加法的方式,就是取对数。

    也就是说:

    [Ans(x)=prod_{i=1}^nF_i(x)=e^{sum_{i=1}^nln F_i(x)} ]

    然而,对每个生成函数都暴力求一次对数复杂度依旧堪忧。

    但是啊,考虑到我们求的是(frac1{1-x^{v_i}})的对数,显然有(lnfrac 1{1-x^{v_i}}=-ln(1-x^{v_i})),而(ln(1-x^a))是有一个简便的计算公式的。

    (ln(1-x^a))

    (G(x)=ln(1-x^a)),首先两边同时求导:

    [G'(x)=frac{(1-x^a)'}{1-x^a}=frac{-a imes x^{a-1}}{1-x^a} ]

    反向利用等比数列求和公式把(1-x^a)化回去得到:

    [G'(x)=-a imes x^{a-1} imessum_{k=0}^{+infty}x^{a imes k}=-sum_{k=0}^{+infty}a imes x^{a imes(k+1)-1} ]

    不妨令枚举的(k)(1),因此就有:

    [G'(x)=-sum_{k=1}^{+infty}ax^{ak-1} ]

    接着我们把(G'(x))还原回(G(x)),得到:

    [G(x)=-sum_{k=1}^{+infty}frac1{ak} imes ax^{ak}=-sum_{k=1}^{+infty}frac1kx^{ak} ]

    总结一下,也就是说:

    [ln (1-x^a)=-sum_{k=1}^{+infty}frac1kx^{ak} ]

    求解最终答案

    我们把(ln (1-x^a)=-sum_{k=1}^{+infty}frac1kx^{ak})这一式子代回去,于是:

    [ln F_i(x)=sum_{k=1}^{+infty}frac1kx^{v_ik} ]

    显然,因为我们最后只要知道答案多项式的前(m)项,那么对于每一个(ln F_i(x))也只用保留前(m)项即可。

    不过现在我们要的是(e^{sum_{i=1}^nln F_i(x)}),只要先求出(sum_{i=1}^nln F_i(x))再做一个多项式(Exp)即可。

    至于(sum_{i=1}^nln F_i(x)),我们可以统计(cnt_x)表示有多少(v_i=x),然后对于每个(x)(lfloorfrac mx floor)的复杂度去修改一遍最终多项式的系数,那么总复杂度就是调和级数。

    代码:(O(mlogm))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define X 998244353
    using namespace std;
    int n,m,f[N+5],g[N+5],c[N+5],Inv[N+5];
    I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,E=(C=FO)+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    namespace Poly//多项式板子
    {
    	#define Init(n) P=1,L=0;W(P<=2*(n)) P<<=1,++L;
    		for(i=0;i^P;++i) A[i]=B[i]=0,R[i]=((R[i>>1]>>1)|((i&1)<<L-1));
    	int PR=3,P,L,R[N<<2],p[N+5],A[N<<2],B[N<<2];
    	I void NTT(int* s,CI op)
    	{
    		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x);
    		for(i=1;i^P;i<<=1) for(U=QP(QP(PR,op),(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,k=0;
    			k^i;++k,S=1LL*S*U%X) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
    	}
    	I void Inv(CI n,int* a,int* b)
    	{
    		if(!n) return (void)(b[0]=QP(a[0],X-2));RI i;Inv(n>>1,a,b);
    		Init(n);for(i=0;i<=n;++i) A[i]=a[i],B[i]=b[i];
    		for(NTT(A,1),NTT(B,1),i=0;i^P;++i) A[i]=(2LL*B[i]-1LL*A[i]*B[i]%X*B[i]%X+X)%X;
    		RI t=QP(P,X-2);for(NTT(A,X-2),i=0;i<=n;++i) b[i]=1LL*A[i]*t%X;
    	}
    	I void Ln(CI n,int* a,int* b)
    	{
    		RI i;for(i=0;i<=n;++i) b[i]=0;Inv(n,a,b);
    		Init(n-1);for(i=0;i<=n-1;++i) A[i]=1LL*a[i+1]*(i+1)%X,B[i]=b[i];
    		for(NTT(A,1),NTT(B,1),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
    		RI t=QP(P,X-2);for(NTT(A,X-2),b[0]=i=0;i^n;++i) b[i+1]=1LL*A[i]*t%X*QP(i+1,X-2)%X;
    	}
    	int q[N+5];I void Exp(CI n,int* a,int* b)//多项式Exp
    	{
    		if(!n) return (void)(b[0]=1);RI i;Exp(n>>1,a,b);
    		Ln(n,b,p),Init(n);for(i=0;i<=n;++i) A[i]=b[i],B[i]=(!i-p[i]+a[i]+X)%X;
    		for(NTT(A,1),NTT(B,1),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
    		RI t=QP(P,X-2);for(NTT(A,X-2),i=0;i<=n;++i) b[i]=1LL*A[i]*t%X;
    	}
    }
    int main()
    {
    	RI i,j,x;for(F.read(n),F.read(m),i=1;i<=n;++i) F.read(x),++c[x];//统计每种v[i]的个数
    	for(Inv[0]=Inv[1]=1,i=2;i<=m;++i) Inv[i]=1LL*(X-X/i)*Inv[X%i]%X;//线性求逆元
    	for(i=1;i<=m;++i) if(c[i]) for(j=1;i*j<=m;++j) f[i*j]=(1LL*c[i]*Inv[j]+f[i*j])%X;//调和级数复杂度求出系数
    	for(Poly::Exp(m,f,g),i=1;i<=m;++i) F.writeln(g[i]);return F.clear(),0;//多项式Exp后输出答案
    }
    
  • 相关阅读:
    Linux系统下安装rz/sz命令及使用说明(文件上传下载)
    html 手机端click 事件延迟问题(fastclick.js使用方法)
    html 手机端click 事件去掉黑色阴影效果
    页面在Native端滚动时模拟原生的弹性滚动效果
    在 2016 年学 JavaScript 是一种什么样的体验?
    凸包---(简单概念)
    .NET框架
    项目使用技术-张子阳推荐
    MessageBox页面消息弹出框类
    c# DES 加密解密方法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4389.html
Copyright © 2011-2022 走看看