【洛谷5394】【模板】下降幂多项式乘法

点此看题面

  • 给定一个(n)次的下降幂多项式(A(x))和一个(m)次的下降幂多项式(B(x)),求(A(x)*B(x))
  • (n,mle10^5)

总之这道题给我的感觉就是下降幂超级神奇,然而让我自己想肯定啥也想不出来。。。

下降幂多项式的生成函数

我们设下降幂多项式(F(x))点值指数型生成函数(G(x)),显然有:

[G(x)=sum_{i=0}^{+infty}frac{F(i)}{i!}x^i ]

显然,这个函数是线性的,也就是说我们可以单独考虑每一项的式子。

因此我们以(x^{underline n})为例,设它对应点值的指数型生成函数为(G_n(x)),得到:(因为(i<n)(i^{underline{n}}=0),所以枚举下界可以直接取(n)

[G_n(x)=sum_{i=n}^{+infty}frac{i^{underline{n}}}{i!}x^i=sum_{i=n}^{+infty}frac1{(i-n)!}x^i=sum_{i=0}^{+infty}frac1{i!}x^{i+n}=x^nsum_{i=0}^{+infty}frac{x^i}{i!}=x^ne^x ]

然后我们再把这个结果代入到原式中,就可以发现:

[G(x)=sum_{i=0}^nf_iG_i(x)=sum_{i=0}^nf_ix^ie^x=e^xsum_{i=0}^nf_ix^i=e^xF(x) ]

推出这样的式子,意味着我们直接求出了点值的指数型生成函数和下降幂多项式系数的生成函数之间的关系!

这应该是一个非常有意思且实用的结论。

下降幂多项式乘法

有了上面这一结论,下降幂多项式乘法的具体实现就很显然了。

首先,我们给(A(x))(B(x))都卷上一个(e^x=sum_{i=0}^{n+m}frac{x^i}{i!}),然后就得到了它俩点值的指数型生成函数。

搞出点值就可以直接给它们做乘法了,但注意这是指数型生成函数,两个乘在一起相当于多除了一次阶乘,因此要给它乘回去。

接着我们给做完乘法的生成函数(A(x))卷上一个(e^{-x}=sum_{i=0}^{n+m}frac{(-x)^i}{i!}),就把它重新变回了下降幂多项式系数的生成函数,这样一来就结束了。

代码:(O(nlogn))

#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,a[2*N+5],b[N+5],Fac[2*N+5],IFac[2*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;}
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc(' ');}
}using namespace FastIO;
namespace Poly
{
	#define PR 3
	int P,L,A[N<<3],B[N<<3],e[N<<3],R[N<<3];I void T(int* s,CI op)
	{
		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(swap(s[i],s[R[i]]),0);
		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 DMul(CI n,int* a,CI m,int* b)//下降幂乘法
	{
		RI i,t;P=1,L=0;W(P<=2*(n+m)) P<<=1,++L;for(t=QP(P,X-2),i=0;i^P;++i) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
		for(i=0;i<=n;++i) A[i]=a[i];for(i=0;i<=m;++i) B[i]=b[i];for(i=0;i<=n+m;++i) e[i]=IFac[i];//记录两个下降幂多项式和e^x的系数
		for(T(A,1),T(B,1),T(e,1),i=0;i^P;++i) A[i]=1LL*A[i]*e[i]%X,B[i]=1LL*B[i]*e[i]%X,e[i]=0;//给A,B卷上e^x
		for(T(A,X-2),T(B,X-2),i=0;i<=n+m;++i) A[i]=1LL*A[i]*B[i]%X*Fac[i]%X*t%X*t%X;W(i^P) A[i++]=0;//点值直接相乘,注意乘回一次阶乘
		for(i=0;i<=n+m;++i) e[i]=(i&1)?X-IFac[i]:IFac[i];//记录e^(-x)
		for(T(A,1),T(e,1),i=0;i^P;++i) A[i]=1LL*A[i]*e[i]%X;for(T(A,X-2),i=0;i<=n+m;++i) a[i]=1LL*A[i]*t%X;//把A还原回系数
	}
}
int main()
{
	RI i;for(read(n,m),Fac[0]=i=1;i<=n+m;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
	for(IFac[i=n+m]=QP(Fac[n+m],X-2);i;--i) IFac[i-1]=1LL*IFac[i]*i%X;//预处理阶乘逆元
	for(i=0;i<=n;++i) read(a[i]);for(i=0;i<=m;++i) read(b[i]);
	for(Poly::DMul(n,a,m,b),i=0;i<=n+m;++i) write(a[i]);return clear(),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/DMul.html