zoukankan      html  css  js  c++  java
  • 【LuoguP5383】[模板]普通多项式转下降幂多项式

    传送门

    Sol

    (怎么老是有人喜欢出新的多项式毒瘤板子,懒得整到一起了)

    核心就是把 幂用下降幂来代替。

    使用斯特林数展开幂为下降幂:

    [x^n=sum_{i=0}^n{xchoose i}i!S(n,i)=sum_{i=0}^nS(n,i)x^{underline i} ]

    那么要求的多项式:

    [sum_{i=0}^{n-1}a_ix^i=sum_{i=0}^{n-1}a_isum_{j=0}^jS(i,j)x^{underline j} ]

    交换求和顺序:

    [sum_{j=0}^{n-1}x^{underline j}sum_{i=j}^{n-1} a_iS(i,j) ]

    那么求出后面那个东西就行了。由于当 (i<j)(S(i,j)=0),所以 (i) 可以从 (0) 开始枚举。这个就是一个要求一列的斯特林数的模型。

    把斯特林数拆开:

    [sum_{i=0}^{n-1}frac{a_i}{j!}sum_{k=0}^j (-1)^{j-k}{jchoose k}k^i ]

    组合数拆开形成卷积:

    [sum_{k=0}^jfrac{(-1)^{j-k}}{(j-k)!}*sum_{i=0}^{n-1}frac{a_ik^i}{k!} ]

    (f_k=frac{(-1)^k}{k!},g_k=sum_{i=0}^{n-1}frac{a_ik^i}{k!}) ,那么对 (F(x))(G(x))做卷积即可。

    (G(x)) 需要多项式多点求值。

    code:

    #include<bits/stdc++.h>
    #define Set(a,b) memset(a,b,sizeof(a))
    #define Clear(a,_begin_,_end_) for(int i=_begin_;i<_end_;++i) a[i]=0
    #define Input_Array(a,_begin_,_end_) for(int i=_begin_;i<_end_;++i) init(a[i])
    #define __ NULL
    using namespace std;
    const int N=1e5+10,MAXN=N<<2,MAXM=5e6;
    typedef vector<int> Poly;
    template <typename T> inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;return;
    }typedef double db;
    typedef long long ll;
    int Inv[MAXN],rader[MAXN];
    const int mod=998244353,phi=998244352,SIZE=sizeof(rader),inv2=499122177;
    template<typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
    template<typename T>inline void Dec(T&x,int y){x-=y;if(x <	0) x+=mod;return;}
    template<typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
    inline int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
    inline int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
    inline int Init(int n){int len=1,up=-1;while(len<=n) len<<=1,++up;for(int i=0;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);return len;}
    inline void Calc_Inversion(){Inv[1]=1;for(int i=2;i<MAXN;++i) Inv[i]=(ll)(mod-mod/i)*Inv[mod%i]%mod;return;}
    namespace NTT{
    	int wn[30],iwn[30];
    	inline void Calcw(){for(int i=0;i<30;++i) wn[i]=fpow(3,phi/(1<<i)),iwn[i]=fpow(wn[i],mod-2);}
    	inline void NTT(int*A,int n,int f){
    		for(int i=0;i<n;++i) if(rader[i]>i) swap(A[i],A[rader[i]]);
    		for(int i=1,h=1;i<n;++h,i<<=1){
    			int W=(~f)? wn[h]:iwn[h];
    			for(int j=0,p=i<<1;j<n;j+=p){
    				for(int w=1,k=0;k<i;++k,w=(ll)w*W%mod){
    					int X=A[j|k],Y=(ll)w*A[j|k|i]%mod;
    					A[j|k]=Sum(X,Y),A[j|k|i]=Dif(X,Y);
    				}
    			}
    		}if(!~f) for(int i=0;i<n;++i) A[i]=(ll)A[i]*Inv[n]%mod;
    		return;
    	}
    	inline void Mul(int*a,int*b,int*c,int n,int m) {
    		int L=n+m-1;int len=Init(L);static int A[MAXN],B[MAXN];
    		for(int i=0;i<n;++i) A[i]=a[i];for(int i=0;i<m;++i) B[i]=b[i];
    		Clear(A,n,len);Clear(B,m,len);NTT(A,len,1),NTT(B,len,1);
    		for(int i=0;i<len;++i) c[i]=(ll)A[i]*B[i]%mod;
    		NTT(c,len,-1);return;
    	}
    	inline void Poly_Inv(int*F,int*I,int n){
    		if(n==1) {memset(I,0,SIZE);I[0]=fpow(F[0],mod-2);return;}
    		Poly_Inv(F,I,(n+1)>>1);int L=n<<1,len=Init(L);
    		static int A[MAXN];for(int i=0;i<n;++i) A[i]=F[i];Clear(A,n,len);
    		NTT(I,len,1);NTT(A,len,1);
    		for(int i=0;i<len;++i) I[i]=Dif(Sum(I[i],I[i]),(ll)I[i]*I[i]%mod*A[i]%mod);
    		NTT(I,len,-1);Clear(I,n,len);return;
    	}
    	inline void Poly_Mod(int*A,int*B,int*Q,int*R,int n,int m){
    		if(n<m) {for(int i=0;i<=n;++i) R[i]=A[i];return;}
    		static int C[MAXN],D[MAXN],E[MAXN];
    		const int r=(n-m)<<1;int len=1;while(len<=r)len<<=1;
    		for(int i=0;i<=n-m;++i) D[i]=A[n-i];Clear(D,n-m+1,len);
    		for(int i=0;i<=m;++i)   E[i]=B[m-i];Clear(E,m+1,len);
    		Poly_Inv(E,C,n-m+1);len=Init(r);NTT(C,len,1),NTT(D,len,1);
    		for(int i=0;i<len;++i) C[i]=(ll)C[i]*D[i]%mod;
    		NTT(C,len,-1);reverse(E,E+1+m),reverse(C,C+1+n-m);
    		if(Q) for(int i=0;i<=n-m;++i) Q[i]=C[i];
    		len=Init(n);Clear(C,n-m+1,len);Clear(E,m+1,len);
    		NTT(C,len,1),NTT(E,len,1);
    		for(int i=0;i<len;++i) C[i]=(ll)C[i]*E[i]%mod;
    		NTT(C,len,-1);for(int i=0;i<m;++i) R[i]=Dif(A[i],C[i]);
    		return;
    	}
    #define ls (u<<1)
    #define rs (u<<1|1)
    	int POOL[MAXM],cnt=0;
    	int *P[MAXN],*F[MAXN],*G[MAXN],X[N],*val;
    	inline int* Neospace(int len){int*ret=&POOL[cnt];cnt+=len;return ret;}
    	inline int Calc(int*F,int n,const int x){int X=1,ret=0;for(int i=0;i<n;++i) Inc(ret,(ll)F[i]*X%mod),X=(ll)X*x%mod;return ret;}
    	inline void Divide(int u,int l,int r){P[u]=NULL;//分治+NTT , 保留了中间的结果
    		if(l==r) {P[u]=Neospace(2);P[u][0]=mod-X[l];P[u][1]=1;return;}
    		static int L[MAXN],R[MAXN];int mid=(l+r)>>1;int LS=ls,RS=rs;
    		Divide(LS,l,mid);Divide(RS,mid+1,r);
    		int n=r-l+2,nl=mid-l+2,nr=r-mid+1;
    		for(int i=0;i<nl;++i) L[i]=P[LS][i];
    		for(int i=0;i<nr;++i) R[i]=P[RS][i];
    		Mul(L,R,L,nl,nr);P[u]=Neospace(n);
    		for(int i=0;i<n;++i) P[u][i]=L[i];
    		return;
    	}
    	inline void Poly_Evaluate(int u,int l,int r){// 多点求值
    		if(r-l+1<=500) {for(int i=l;i<=r;++i) val[i]=Calc(F[u],r-l+1,X[i]);return;}// 长度小的暴力计算
    		int mid=(l+r)>>1,LS=ls,RS=rs;
    		int n=r-l+1,nl=mid-l+1,nr=r-mid;
    		static int R[MAXN];
    		F[LS]=Neospace(nl),F[RS]=Neospace(nr);
    		Poly_Mod(F[u],P[LS],__,R,n-1,nl);
    		for(int i=0;i<nl;++i) F[LS][i]=R[i];
    		Poly_Mod(F[u],P[RS],__,R,n-1,nr);
    		for(int i=0;i<nr;++i) F[RS][i]=R[i];
    		Poly_Evaluate(LS,l,mid);
    		Poly_Evaluate(RS,mid+1,r);
    		return;
    	}
    	inline void Solve_Evaluation(int*A,int*_X,int*ans,int n,int m){
    		cnt=0;F[1]=Neospace(m);val=ans;
    		for(int i=1;i<=m;++i) X[i]=_X[i];Divide(1,1,m);
    		Poly_Mod(A,P[1],__,F[1],n-1,m);//注意最开始的多项式也要取一次模
    		Poly_Evaluate(1,1,m);return;
    	}
    }
    int fac[N],finv[N];
    int main()
    {
    	Calc_Inversion();NTT::Calcw();
    	int n;fac[0]=finv[0]=1;init(n);
    	for(int i=1;i<n;++i) fac[i]=(ll)fac[i-1]*i%mod,finv[i]=(ll)finv[i-1]*Inv[i]%mod;
    	static int F[MAXN],A[MAXN],X[MAXN];
    	for(int i=0;i<n;++i) init(A[i]),X[i+1]=i,F[i]=(i&1)? (mod-finv[i]):finv[i];
    	NTT::Solve_Evaluation(A,X,X,n,n);
    	for(int i=0;i<n;++i) X[i]=(ll)X[i+1]*finv[i]%mod;X[n]=0;
    	NTT::Mul(X,F,F,n,n);
    	for(int i=0;i<n;++i) printf("%d ",F[i]);putchar('
    ');
    	return 0;
    }
    
    
  • 相关阅读:
    SecureRandom
    一个不错的架构图:基于SpringCloud的微服务项目
    Android 增量更新完全解析 是增量不是热修复
    Android热修复方案比较
    Android Activity作为dialog对话框的使用详细介绍
    Android 微信分享不出去?四步搞定!
    Android:用签名打包后微信分享失效
    Android 根据QQ号跳转到QQ聊天界面
    Android fragment-findFragmentByTag 始终返回 null
    Android RecyclerView遇到notifyDataSetChanged无效时的解决方案
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10880025.html
Copyright © 2011-2022 走看看