• 多项式求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
    ",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
    ",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
    ",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
    ",(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
    ");
    	return 0;
    }
    

    感觉生成函数什么的还是很好玩的,非常想找时间学一学

    不过貌似NOI用处不大(雾

  • 相关阅读:
    CSS3 背景
    CSS3 边框
    CSS3中的transform变形
    兼容IE与firefox火狐的回车事件(js与jquery)
    JS相关链接
    JS操作DOM元素属性和方法
    用js给html设置style
    JavaScript数学函数(一)
    [JS] 如何清空file input框 [整理]
    未在本地计算机上注册Microsoft.ACE.OLEDB.12.0提供程序(Oledb)
  • 原文地址:https://www.cnblogs.com/joyouth/p/5604618.html
Copyright © 2020-2023  润新知