zoukankan      html  css  js  c++  java
  • 【洛谷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;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    查依赖的时候发现 ldd: not found 的话,可以用 readelf 喔。
    【rv1126】host Python 没有内置 pip ,所以需要手动调用 get-pip.py 为 Python pip 安装指定包。
    MaixPy3 Linux 通用模块设计
    剑指 Offer 27. 二叉树的镜像
    Pycocotools安装艰辛历程
    性能测试之常见性能指标
    libuv事件循环中的三种句柄
    libuv线程通信
    libuv工作队列
    libuv中实现tcp服务器
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/DMul.html
Copyright © 2011-2022 走看看