普通多项式转下降幂多项式小结

前置芝士

斯特林数

正题

对于给定的多项式 F ( x ) = ∑ i = 0 n a i x i F(x)=\sum_{i=0}^n a_i x^i F(x)=i=0naixi,求出一个下降幂多项式 G ( x ) = ∑ i = 0 n b i x i ‾ G(x)=\sum_{i=0}^n b_i x^{\underline i} G(x)=i=0nbixi,满足 F ( x ) = G ( x ) F(x)=G(x) F(x)=G(x)

主要用到的技巧就是利用第二类斯特林数展开 x n x^n xn,即 x n = ∑ j = 0 n C x j j ! S ( n , j ) x^n=\sum_{j=0}^n C_x^j j! S(n,j) xn=j=0nCxjj!S(n,j),可以发现 C x j j ! = x ! ( x − j ) ! C_x^j j!=\dfrac {x!} {(x-j)!} Cxjj!=(xj)!x!,即 x j ‾ x^{\underline j} xj,于是有 x n = ∑ j = 0 n S ( n , j ) x j ‾ x^n=\sum_{j=0}^n S(n,j) x^{\underline j} xn=j=0nS(n,j)xj

推推柿子:
F ( x ) = ∑ i = 0 n a i x i = ∑ i = 0 n a i ∑ j = 0 n S ( i , j ) x j ‾ = ∑ j = 0 n x j ‾ ∑ i = 0 n S ( i , j ) a i \begin{aligned} F(x)&=\sum_{i=0}^n a_i x^i\\ &=\sum_{i=0}^n a_i \sum_{j=0}^n S(i,j) x^{\underline j}\\ &=\sum_{j=0}^n x^{\underline j} \sum_{i=0}^n S(i,j) a_i\\ \end{aligned} F(x)=i=0naixi=i=0naij=0nS(i,j)xj=j=0nxji=0nS(i,j)ai

于是就得到了每一项的系数,考虑怎么求这个系数。

先拆开斯特林数:
第   k   项 系 数 = ∑ i = 0 n S ( i , k ) a i = ∑ i = 0 n a i × 1 k ! ∑ j = 0 n ( − 1 ) k − j ( k j ) j i = ∑ i = 0 n a i ∑ j = 0 n ( − 1 ) k − j 1 j ! ( k − j ) ! j i = ∑ j = 0 n ( − 1 ) k − j ( k − j ) ! ∑ i = 0 n a i j i j ! \begin{aligned} 第~k~项系数&=\sum_{i=0}^n S(i,k)a_i\\ &=\sum_{i=0}^n a_i\times \frac 1 {k!} \sum_{j=0}^n (-1)^{k-j} {k\choose j} j^i\\ &=\sum_{i=0}^n a_i \sum_{j=0}^n (-1)^{k-j} \frac {1} {j!(k-j)!} j^i\\ &=\sum_{j=0}^n \frac {(-1)^{k-j}} {(k-j)!} \sum_{i=0}^n \frac {a_i j^i} {j!} \end{aligned}  k =i=0nS(i,k)ai=i=0nai×k!1j=0n(1)kj(jk)ji=i=0naij=0n(1)kjj!(kj)!1ji=j=0n(kj)!(1)kji=0nj!aiji

发现后面那个 ∑ i = 0 n a i j i j ! \sum_{i=0}^n \dfrac {a_i j^i} {j!} i=0nj!aiji 其实就是 F ( j ) j ! \dfrac {F(j)} {j!} j!F(j),一个多项式多点求值就可以求出,记 H j = F ( j ) H_j=F(j) Hj=F(j),那么有
第   k   项 系 数 = ∑ j = 0 n ( − 1 ) k − j ( k − j ) ! H j 第~k~项系数=\sum_{j=0}^n \frac {(-1)^{k-j}} {(k-j)!} H_j  k =j=0n(kj)!(1)kjHj

这是个卷积状物,于是乎就做完了。

模板题传送门

代码跑的还算快吧qwq,不开 O2 大概是 9.3 s 9.3s 9.3s

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 600010
#define mod 998244353
#define bin(x) (1<<(x))
#define MS(f,x) memset(f,0,4<<(x))
#define CP(f,g,x) memcpy(f,g,(x)<<2)

int n,F[maxn],G[maxn];
int ksm(int x,int y){
    
    int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int inv[maxn],w[maxn],log_2[maxn];void prep(int N){
    
    
	inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,log_2[i]=ceil(log2(i));
	for(int i=1,wn;i<N;i<<=1){
    
    
		w[i]=1;wn=ksm(3,(mod-1)/(i<<1));
		for(int j=1;j<i;j++)w[i+j]=1ll*w[i+j-1]*wn%mod;
	}
}
int limit,r[maxn];void work(int lg){
    
    for(int i=0;i<bin(lg);i++)r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));}
int add(int x){
    
    return x>=mod?x-mod:x;};
int dec(int x){
    
    return x<0?x+mod:x;}
void ntt(int *f,int lg,int type=0)
{
    
    
	limit=bin(lg);if(type)reverse(f+1,f+limit);
	for(int i=1;i<limit;i++)if(i<r[i])swap(f[i],f[r[i]]);
	for(int mid=1,t;mid<limit;mid<<=1)for(int j=0;j<limit;j+=(mid<<1))for(int i=0;i<mid;i++)
	{
    
    t=1ll*f[j+i+mid]*w[mid+i]%mod;f[j+i+mid]=dec(f[j+i]-t);f[j+i]=add(f[j+i]+t);}
	if(type)for(int i=0;i<limit;i++)f[i]=1ll*f[i]*inv[limit]%mod;
}
void NTT(int *f,int *g,int ln){
    
    
	int lg=log_2[ln];work(lg);ntt(f,lg);ntt(g,lg);
	for(int i=0;i<bin(lg);i++)f[i]=1ll*f[i]*g[i]%mod;ntt(f,lg,1);
}
int A[maxn],B[maxn],C[maxn],D[maxn],E[maxn],H[maxn];
void getinv(int *f,int *g,int ln)
{
    
    
	if(ln==1){
    
    g[0]=ksm(f[0],mod-2);return;}getinv(f,g,(ln+1)>>1);
	int lg=log_2[ln<<1];work(lg);MS(A,lg);MS(B,lg);CP(A,f,ln);CP(B,g,ln);
	ntt(A,lg);ntt(B,lg);for(int i=0;i<bin(lg);i++)B[i]=1ll*(2-1ll*A[i]*B[i]%mod+mod)*B[i]%mod;
	ntt(B,lg,1);for(int i=0;i<ln;i++)g[i]=B[i];
}
void rev(int *f,int *g,int ln){
    
    for(int i=0;i<ln;i++)g[i]=f[ln-1-i];}
void getdiv(int *f,int *g,int *q,int ln1,int ln2){
    
    
	MS(C,log_2[ln1<<1]);MS(D,log_2[ln1<<1]);rev(f,C,ln1);rev(g,D,ln2);
	for(int i=ln1-ln2+1;i<ln1;i++)C[i]=D[i]=0;
	MS(E,log_2[ln1<<1]);getinv(D,E,ln1-ln2+1);NTT(C,E,(ln1-ln2+1)<<1);rev(C,q,ln1-ln2+1);
}
void getmod(int *f,int *g,int *q,int *r,int ln1,int ln2){
    
    
	MS(C,log_2[ln1<<1]);MS(D,log_2[ln1<<1]);CP(C,g,ln1);CP(D,q,ln1);
	NTT(C,D,ln1);for(int i=0;i<ln2;i++)r[i]=dec(f[i]-C[i]);
}
void getmod(int *f,int *g,int *r,int ln1,int ln2){
    
    
	if(ln1<ln2){
    
    CP(r,f,ln1);return;}
	MS(H,log_2[ln1<<1]);getdiv(f,g,H,ln1,ln2);getmod(f,g,H,r,ln1,ln2);
}
int *P[maxn],*R[maxn];int kk(int d,int id){
    
    return (1<<d)+id;}
#define ID kk(d,id)
void FZ_FFT(int l,int r,int d,int id)
{
    
    
	P[ID]=new int[bin(log_2[r-l+2]+1)];R[ID]=new int[bin(log_2[r-l+2]+1)];
	if(l==r){
    
    P[ID][0]=mod-l;P[ID][1]=1;return;}int mid=l+r>>1;
	FZ_FFT(l,mid,d+1,id<<1);FZ_FFT(mid+1,r,d+1,(id<<1)+1);
	int lg=log_2[(r-l+2)<<1];MS(P[ID],lg);MS(E,lg);
	CP(P[ID],P[kk(d+1,id<<1)],mid-l+2);CP(E,P[kk(d+1,(id<<1)+1)],r-mid+1);NTT(P[ID],E,r-l+2);
}
void evalu(int l,int r,int *FA,int ln,int d,int id)
{
    
    
	getmod(FA,P[ID],R[ID],ln,r-l+2);
	if(r-l<=300){
    
    for(int i=l;i<=r;i++){
    
    
	for(int j=r-l;j>=0;j--)G[i]=add(1ll*G[i]*i%mod+R[ID][j]);}return;}
	int mid=l+r>>1;evalu(l,mid,R[ID],r-l+1,d+1,id<<1);evalu(mid+1,r,R[ID],r-l+1,d+1,(id<<1)+1);
}
int fac[maxn],inv_fac[maxn];
void work(){
    
    fac[0]=inv_fac[0]=1;for(int i=1;i<(n<<1);i++)fac[i]=1ll*fac[i-1]*i%mod,inv_fac[i]=1ll*inv_fac[i-1]*inv[i]%mod;}

int main()
{
    
    
	scanf("%d",&n);prep(n<<2);work();
	for(int i=0;i<n;i++)scanf("%d",&F[i]);
	FZ_FFT(0,n-1,0,0);evalu(0,n-1,F,n,0,0);
	for(int i=0;i<n;i++)G[i]=1ll*G[i]*inv_fac[i]%mod,F[i]=(i&1?mod-inv_fac[i]:inv_fac[i]);
	NTT(F,G,n<<1);
	for(int i=0;i<n;i++)printf("%d ",F[i]);
}

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/107017907