多項式求ln,求exp,開方,快速冪 學習總結


按理說Po姐姐三月份來講課的時候我就應該學了

但是當時覺得比較難加上自己比較懶,所以就QAQ了

現在不得不重新弄一遍了

 

首先說多項式求ln

設G(x)=lnF(x)

我們兩邊求導可以得到G'(x)=F‘(x)/F(x)

則G(x)就是F’(x)/F(x)的積分

我們知道多項式求導和積分是O(n)的,多項式求逆是O(nlogn)的

所以總時間復雜度O(nlogn)

多項式求ln一般解決的問題是這樣的

設多項式f表示一些奇怪的東西,由一些奇怪的東西有序組成的方案為

f^1+f^2+f^3…… 化簡之后得到多項式求逆的式子

而由這些奇怪的東西無序組成的方案為

f^1/1!+f^2/2!……

由泰勒展開我們知道化簡后為e^f

則若我們知道e^f,求f就需要多項式求ln了

這樣推導非常的優美

譬如說BZOJ 3456 城市規划

設答案為多項式f,設n個點的無向圖個數為多項式g

不難發現無向圖是由若干個無序聯通塊組成的

我們得到式子g=e^f

而多項式g是非常好構造的,f=ln(g)

多項式求ln即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define G 3
using namespace std;
 
typedef long long LL;
const int maxn=300010;
const int mod=1004535809;
int n,N,len,rev[maxn];
int jc[maxn],inv[maxn];
int g[maxn],f[maxn],w[maxn];
 
int pow_mod(int v,int p){
    int tmp=1;
    while(p){
        if(p&1)tmp=1LL*tmp*v%mod;
        v=1LL*v*v%mod;p>>=1;
    }return tmp;
}
void FFT(int *A,int n,int flag){
    for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
    for(int k=2;k<=n;k<<=1){
        int mk=(k>>1);
        int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
        w[0]=1;
        for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
        for(int i=0;i<n;i+=k){
            for(int j=0;j<mk;++j){
                int a=i+j,b=i+j+mk;
                int x=A[a],y=1LL*A[b]*w[j]%mod;
                A[a]=(x+y)%mod;
                A[b]=x-y;if(A[b]<0)A[b]+=mod;
            }
        }
    }
    if(flag==-1){
        int c=pow_mod(n,mod-2);
        for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
    }
}
void Get_inv(int n){
    if(n==1){
        f[0]=pow_mod(g[0],mod-2);
        return;
    }
    Get_inv(n>>1);
    int now=(n<<1);
    for(len=0;(1<<len)<now;++len);
    for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
    static int tmp[maxn];
    for(int i=0;i<n;++i)tmp[i]=g[i];
    FFT(tmp,now,1);FFT(f,now,1);
    for(int i=0;i<now;++i)f[i]=1LL*f[i]*(2LL-1LL*f[i]*tmp[i]%mod+mod)%mod;
    FFT(f,now,-1);
    memset(f+n,0,sizeof(int)*n);
}
void Get_Dao(){
    g[N]=0;
    for(int i=0;i<N;++i)g[i]=1LL*g[i+1]*(i+1)%mod;
}
void Get_Fen(){
    f[0]=0;
    for(int i=N-1;i>=0;--i)f[i]=1LL*f[i-1]*pow_mod(i,mod-2)%mod;
}
 
int main(){
    scanf("%d",&n);
    for(N=1;N<=n;N<<=1);
    jc[0]=1;
    for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
    inv[N-1]=pow_mod(jc[N-1],mod-2);
    for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
    for(int i=0;i<N;++i){
        int tmp=(1LL*i*(i-1)/2)%(mod-1);
        g[i]=1LL*pow_mod(2,tmp)*inv[i]%mod;
    }
    Get_inv(N);Get_Dao();N<<=1;
    for(len=0;(1<<len)<N;++len);
    for(int i=0;i<N;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
    FFT(g,N,1);FFT(f,N,1);
    for(int i=0;i<N;++i)f[i]=1LL*f[i]*g[i]%mod;
    FFT(f,N,-1);Get_Fen();
    printf("%d\n",1LL*f[n]*jc[n]%mod);
    return 0;
}

cojs 2358 

首先用多項式求逆可以搞出n個點的DAG的個數,這個不再多說

我們不難發現n個點的DAG是由若干個DAG的弱連通圖無序組成的

多項式求ln即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define G 3
using namespace std;

const int maxn=300010;
const int mod=998244353;
int n,N,len,w[maxn];
int jc[maxn],inv[maxn],rev[maxn];
int f[maxn],Inv[maxn],ln[maxn];

int pow_mod(int v,int p){
	int tmp=1;
	while(p){
		if(p&1)tmp=1LL*tmp*v%mod;
		v=1LL*v*v%mod;p>>=1;
	}return tmp;
}
void FFT(int *A,int n,int flag){
	for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int k=2;k<=n;k<<=1){
		int mk=(k>>1);
		int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
		w[0]=1;
		for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
		for(int i=0;i<n;i+=k){
			for(int j=0;j<mk;++j){
				int a=i+j,b=i+j+mk;
				int x=A[a],y=1LL*A[b]*w[j]%mod;
				A[a]=(x+y)%mod;
				A[b]=x-y;if(A[b]<0)A[b]+=mod;
			}
		}
	}
	if(flag==-1){
		int c=pow_mod(n,mod-2);
		for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
	}return;
}
void Get_dao(int n){
	f[n]=0;
	for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod;
}
void Get_Fen(int n){
	for(int i=n-1;i>=1;--i)ln[i]=1LL*ln[i-1]*pow_mod(i,mod-2)%mod;
	ln[0]=0;
}
void Get_inv(int n){
	if(n==1){
		Inv[0]=pow_mod(f[0],mod-2);
		return;
	}
	Get_inv(n>>1);
	int now=(n<<1);
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	static int tmp[maxn];
	for(int i=0;i<n;++i)tmp[i]=f[i];
	for(int i=n;i<now;++i)tmp[i]=0;
	FFT(Inv,now,1);FFT(tmp,now,1);
	for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*Inv[i]*tmp[i]%mod+mod)%mod;
	FFT(Inv,now,-1);
	memset(Inv+n,0,sizeof(int)*n);
}
void Get_ln(int n){
	int now=(n<<1);
	for(int i=0;i<n;++i)Inv[i]=0;
	Get_inv(n);Get_dao(n);
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(Inv,now,1);FFT(f,now,1);
	for(int i=0;i<now;++i)ln[i]=1LL*Inv[i]*f[i]%mod;
	FFT(ln,now,-1);
	memset(ln+n,0,sizeof(int)*n);
	Get_Fen(n);
}

int main(){
	freopen("dagIV.in","r",stdin);
	freopen("dagIV.out","w",stdout);
	scanf("%d",&n);
	for(N=1;N<=n;N<<=1);
	jc[0]=1;
	for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
	inv[N-1]=pow_mod(jc[N-1],mod-2);
	for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
	for(int i=0;i<N;++i){
		int tmp=(1LL*i*(i-1)/2)%(mod-1);
		f[i]=1LL*pow_mod((mod+1)>>1,tmp)*inv[i]%mod;
		if(i&1)f[i]=mod-f[i];
	}Get_inv(N);
	for(int i=0;i<=n;++i){
		int tmp=(1LL*i*(i-1)/2)%(mod-1);
		f[i]=1LL*Inv[i]*pow_mod(2,tmp)%mod*jc[i]%mod;
		f[i]=1LL*f[i]*inv[i]%mod;
	}
	for(int i=n+1;i<N;++i)f[i]=0;
	Get_ln(N);
	printf("%d\n",1LL*ln[n]*jc[n]%mod);
	return 0;
}

多項式求exp

用處其實跟多項式求ln是相反的

對於式子g=e^f,假設我們知道f,求g就需要用到多項式求exp了

多項式求exp的方式是利用牛頓迭代法倍增

設F(x)=e^A(x)

我們知道若G(F0(x))=0(mod x^n)

我們有G(F(x))=0=G(F0(x))/0!+G‘(F0(x))/1!*(F(x)-F0(x))(mod x^2n)

轉換一下式子我們可以得到F(x)的表達式

我們又知道G(F(x))=lnF(x)-A(x)

帶入上面的式子整理之后我們得到F(x)=F0(x)*(1-lnF0(x)+A(x))

無腦倍增就可以了,每次倍增的時候求ln即可,常數巨大,但還是O(nlogn)的

本來應該出到cojs的題目QAQ但是因為自己的權限掉了QAQ

求前n項的Bell數

在之前的文章里提到了Bell數可以利用CDQ+FFT解決

但是我們也提到了Bell數的生成函數e^(e^x-1)

我們對e^x-1做泰勒展開,之后多項式求exp即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define G 3
using namespace std;

const int mod=998244353;
const int maxn=300010;
int n,N,len,T;
int jc[maxn],inv[maxn],rev[maxn],w[maxn];
int g[maxn],f[maxn],h[maxn],ni[maxn];
int Exp[maxn],ln[maxn],Inv[maxn];
int C[maxn];
struct ASK{
	int n;
}Q[maxn];

int pow_mod(int v,int p){
	int tmp=1;
	while(p){
		if(p&1)tmp=1LL*tmp*v%mod;
		v=1LL*v*v%mod;p>>=1;
	}return tmp;
}
void FFT(int *A,int n,int flag){
	for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int k=2;k<=n;k<<=1){
		int mk=(k>>1);
		int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
		w[0]=1;
		for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
		for(int i=0;i<n;i+=k){
			for(int j=0;j<mk;++j){
				int a=i+j,b=i+j+mk;
				int x=A[a],y=1LL*A[b]*w[j]%mod;
				A[a]=(x+y)%mod;
				A[b]=x-y;if(A[b]<0)A[b]+=mod;
			}
		}
	}
	if(flag==-1){
		int c=pow_mod(n,mod-2);
		for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
	}return;
}
void Get_dao(int n){
	f[n]=0;
	for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod; 
}
void Get_Fen(int n){
	for(int i=n-1;i>=1;--i)ln[i]=1LL*ln[i-1]*ni[i]%mod;
	ln[0]=0;
}
void Get_inv(int n){
	if(n==1){
		Inv[0]=pow_mod(f[0],mod-2);
		return;
	}
	Get_inv(n>>1);
	int now=(n<<1);
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	static int tmp[maxn];
	for(int i=0;i<n;++i)tmp[i]=f[i];
	for(int i=n;i<now;++i)tmp[i]=0;
	FFT(tmp,now,1);FFT(Inv,now,1);
	for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
	FFT(Inv,now,-1);
	memset(Inv+n,0,sizeof(int)*n);
} 
void Get_ln(int n){
	int now=(n<<1);
	for(int i=0;i<n;++i)Inv[i]=0;
	Get_inv(n);Get_dao(n);
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(Inv,now,1);FFT(f,now,1);
	for(int i=0;i<now;++i)ln[i]=1LL*f[i]*Inv[i]%mod;
	FFT(ln,now,-1);
	memset(ln+n,0,sizeof(int)*n);
	Get_Fen(n);
}
void Get_exp(int n){
	if(n==1){Exp[0]=1;return;}
	Get_exp(n>>1);
	int now=(n<<1);
	for(int i=0;i<n;++i)f[i]=Exp[i],h[i]=g[i];
	Get_ln(n);
	for(int i=0;i<now;++i)ln[i]=((i==0)-ln[i]+h[i]+mod)%mod;
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(Exp,now,1);FFT(ln,now,1);
	for(int i=0;i<now;++i)Exp[i]=1LL*Exp[i]*ln[i]%mod;
	FFT(Exp,now,-1);
	memset(Exp+n,0,sizeof(int)*n);
}

int main(){
	freopen("QAQ_Bell.in","r",stdin);
	freopen("QAQ_Bell.ans","w",stdout);
	scanf("%d",&T);
	for(int i=1;i<=T;++i){
		scanf("%d",&Q[i].n);
		n=max(n,Q[i].n);
	}
	for(N=1;N<=n;N<<=1);
	jc[0]=1;ni[0]=ni[1]=1;
	for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
	inv[N-1]=pow_mod(jc[N-1],mod-2);
	for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
	for(int i=2;i<N;++i)ni[i]=(mod-1LL*(mod/i)*ni[mod%i]%mod);
	for(int i=1;i<N;++i)g[i]=inv[i];
	Get_exp(N);
	for(int i=1;i<=T;++i){
		n=Q[i].n;
		printf("%d\n",1LL*Exp[n]*jc[n]%mod);
	}
	return 0;
}

多項式開根

同樣是利用倍增

設G^2(x)=F(x)(mod x^n)

我們得到(G^2(x)-F(x))^2=0(mod x^2n)

又可以得到(G^2(x)+F(x))^2=4*G^2(x)*F(x)(mod x^2n)

即((G^2(x)+F(x))/2*G(x))^2=F(x)(mod x^2n)

顯然括號里面的東西是我們要求的東西,求解即可

注意到多項式開根的前提是常數項可開根,但如果在模意義下並不要求常數項是完全平方數

只要常數項存在二次剩余就可以了,至於求解的話可以利用原根的性質求解

BZOJ 3625

我們設答案多項式為F(x)

我們得到生成函數F(x)=C(x)F^2(x)+1

得到C(x)F^2(x)-F(x)+1=0

F(x)=(1 +or- sqrt(1-4C(x))/2C(x))=2/(1 +or- sqrt(1-4C(x)))

由於多項式求逆要求常數項存在逆,所以可以確定是加號

之后做多項式開根之后多項式求逆即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define G 3
using namespace std;
 
const int maxn=300010;
const int mod=998244353;
int n,m,x,N,len,C;
int f[maxn],rt[maxn],Inv[maxn],rev[maxn];
int w[maxn];
 
void read(int &num){
    num=0;char ch=getchar();
    while(ch<'!')ch=getchar();
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
int pow_mod(int v,int p){
    int tmp=1;
    while(p){
        if(p&1)tmp=1LL*tmp*v%mod;
        v=1LL*v*v%mod;p>>=1;
    }return tmp;
}
void FFT(int *A,int n,int flag){
    for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
    for(int k=2;k<=n;k<<=1){
        int mk=(k>>1);
        int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
        w[0]=1;
        for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
        for(int i=0;i<n;i+=k){
            for(int j=0;j<mk;++j){
                int a=i+j,b=i+j+mk;
                int x=A[a],y=1LL*A[b]*w[j]%mod;
                A[a]=(x+y)%mod;
                A[b]=x-y;if(A[b]<0)A[b]+=mod;
            }
        }
    }
    if(flag==-1){
        int c=pow_mod(n,mod-2);
        for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
    }return;
}
void Get_inv(int n){
    if(n==1){
        Inv[0]=pow_mod(rt[0],mod-2);
        return;
    }
    Get_inv(n>>1);
    int now=(n<<1);
    for(len=0;(1<<len)<now;++len);
    for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
    static int tmp[maxn];
    for(int i=0;i<n;++i)tmp[i]=rt[i];
    for(int i=n;i<now;++i)tmp[i]=0;
    FFT(tmp,now,1);FFT(Inv,now,1);
    for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
    FFT(Inv,now,-1);
    memset(Inv+n,0,sizeof(int)*n);
}
void Get_root(int n){
    if(n==1){rt[0]=1;return;}
    Get_root(n>>1);
    for(int i=0;i<n;++i)Inv[i]=0;
    int now=(n<<1);Get_inv(n);
    static int tmp[maxn];
    for(int i=0;i<n;++i)tmp[i]=f[i];
    for(len=0;(1<<len)<now;++len);
    for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
    FFT(Inv,now,1);FFT(tmp,now,1);
    for(int i=0;i<now;++i)tmp[i]=1LL*tmp[i]*Inv[i]%mod;
    FFT(tmp,now,-1);
    for(int i=0;i<n;++i)rt[i]=1LL*C*(rt[i]+tmp[i])%mod;
}
 
int main(){
    read(n);read(m);C=((mod+1)>>1);
    for(N=1;N<=m;N<<=1);
    for(int i=1;i<=n;++i){
        read(x);
        if(x<=m)f[x]++;
    }
    for(int i=0;i<N;++i)f[i]=((i==0)-4*f[i]+mod)%mod;
    Get_root(N);rt[0]++;
    for(int i=0;i<(N<<1);++i)Inv[i]=0;
    Get_inv(N);
    for(int i=1;i<=m;++i){
        printf("%d\n",(Inv[i]<<1)%mod);
    }return 0;
}

多項式快速冪

即求F^k(x)

我們可以直接做快速冪每次乘完消掉次數界既可以了

但是這樣的做法不夠高大上

我們知道F^k(x)=exp(ln(F^k(x))

而ln(F^k(x))=k*ln(F(x))

我們做多項式求ln,然后系數乘以k之后exp還原即可

時間復雜度O(nlogn)

 

多項式的學習估計就到此結束啦,以后可能會學一些用FFT優化DP,用FFT優化字符串匹配的題目

當然也會寫總結啦

聽說多項式還有什么多點插值,擴展歐幾里得,拉格朗日反演之類的鬼東西

先暫時棄掉咯

最后附上多項式終極模板,也是zcg他們出的毒瘤題目

cojs 2189 帕秋莉的超級多項式

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define G 3
using namespace std;

const int maxn=300010;
const int mod=998244353;
int n,k,N,C,len;
int rev[maxn],w[maxn];
int f[maxn],rt[maxn];
int Inv[maxn],ln[maxn],Exp[maxn];

int pow_mod(int v,int p){
	int tmp=1;
	while(p){
		if(p&1)tmp=1LL*tmp*v%mod;
		v=1LL*v*v%mod;p>>=1;
	}return tmp;
}
void FFT(int *A,int n,int flag){
	for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int k=2;k<=n;k<<=1){
		int mk=(k>>1);
		int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
		w[0]=1;
		for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
		for(int i=0;i<n;i+=k){
			for(int j=0;j<mk;++j){
				int a=i+j,b=i+j+mk;
				int x=A[a],y=1LL*A[b]*w[j]%mod;
				A[a]=(x+y)%mod;
				A[b]=x-y;if(A[b]<0)A[b]+=mod;
			}
		}
	}
	if(flag==-1){
		int c=pow_mod(n,mod-2);
		for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
	}return;
}
void Get_Fen(int *f,int n){
	for(int i=n-1;i>=1;--i)f[i]=1LL*f[i-1]*pow_mod(i,mod-2)%mod;
	f[0]=0;
}
void Get_dao(int *f,int n){
	f[n]=0;
	for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod;
}
void Get_inv(int n,int *h){
	if(n==1){
		Inv[0]=pow_mod(h[0],mod-2);
		return;
	}
	Get_inv(n>>1,h);
	int now=(n<<1);
	static int tmp[maxn];
	for(int i=0;i<n;++i)tmp[i]=h[i];
	for(int i=n;i<now;++i)tmp[i]=0;
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(tmp,now,1);FFT(Inv,now,1);
	for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
	FFT(Inv,now,-1);
	memset(Inv+n,0,sizeof(int)*n);
}
void Get_root(int n){
	if(n==1){
		rt[0]=(int)(sqrt(f[0]));
		return;
	}
	Get_root(n>>1);
	int now=(n<<1);
	for(int i=0;i<now;++i)Inv[i]=0;
	Get_inv(n,rt);
	static int tmp[maxn];
	for(int i=0;i<n;++i)tmp[i]=f[i];
	for(int i=n;i<now;++i)tmp[i]=0;
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(tmp,now,1);FFT(Inv,now,1);
	for(int i=0;i<now;++i)tmp[i]=1LL*tmp[i]*Inv[i]%mod;
	FFT(tmp,now,-1);
	for(int i=0;i<n;++i)rt[i]=1LL*C*(rt[i]+tmp[i])%mod;
}
void Get_ln(int n,int *h){
	int now=(n<<1);
	for(int i=0;i<now;++i)Inv[i]=0;
	Get_inv(n,h);Get_dao(h,n);
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(h,now,1);FFT(Inv,now,1);
	for(int i=0;i<now;++i)ln[i]=1LL*h[i]*Inv[i]%mod;
	FFT(ln,now,-1);
	memset(ln+n,0,sizeof(int)*n);
	Get_Fen(ln,n);
}
void Get_Exp(int n){
	if(n==1){Exp[0]=1;return;}
	Get_Exp(n>>1);
	int now=(n<<1);
	static int g[maxn];
	for(int i=0;i<n;++i)g[i]=Exp[i];
	for(int i=n;i<now;++i)g[i]=0;
	Get_ln(n,g);
	for(int i=0;i<n;++i)ln[i]=((i==0)-ln[i]+f[i]+mod)%mod;
	for(len=0;(1<<len)<now;++len);
	for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
	FFT(ln,now,1);FFT(Exp,now,1);
	for(int i=0;i<now;++i)Exp[i]=1LL*Exp[i]*ln[i]%mod;
	FFT(Exp,now,-1);
	memset(Exp+n,0,sizeof(int)*n);
}

int main(){
	freopen("polynomial.in","r",stdin);
	freopen("polynomial.out","w",stdout);
	scanf("%d",&n);scanf("%d",&k);C=((mod+1)>>1);
	for(int i=0;i<n;++i)scanf("%d",&f[i]);
	for(N=1;N<=n;N<<=1);
	Get_root(N);
	for(int i=0;i<(N<<1);++i)Inv[i]=0;
	Get_inv(N,rt);
	for(int i=0;i<N;++i)f[i]=Inv[i];
	Get_Fen(f,n);
	for(int i=n;i<N;++i)f[i]=0;
	Get_Exp(N);
	for(int i=0;i<N;++i)f[i]=Exp[i];
	for(int i=0;i<(N<<1);++i)Inv[i]=0;
	Get_inv(N,f);
	for(int i=0;i<N;++i)f[i]=Inv[i];
	f[0]++;
	Get_ln(N,f);
	for(int i=0;i<N;++i)f[i]=ln[i];
	f[0]++;
	for(int i=N+1;i<(N<<1);++i)f[i]=0;
	Get_ln(N,f);
	for(int i=0;i<N;++i)f[i]=1LL*k*ln[i]%mod;
	for(int i=0;i<(N<<1);++i)Exp[i]=0;
	Get_Exp(N);
	for(int i=1;i<n;++i)printf("%d ",1LL*Exp[i]*i%mod);
	printf("0\n");
	return 0;
}

感覺生成函數什么的還是很好玩的,非常想找時間學一學

不過貌似NOI用處不大(霧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM