记录编号 242137 评测结果 AAAAAAAAAA
题目名称 [HZOI 2015] 帕秋莉的超级多项式 最终得分 100
用户昵称 Gravatarstdafx.h 是否通过 通过
代码语言 C++ 运行时间 36.974 s
提交时间 2016-03-26 16:35:01 内存使用 32.64 MiB
显示代码纯文本
#define maxn 530010ul

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>

#define ll long long

int G,P=119*(1<<23)+1;

namespace polynomial{
    int ksm(int p,int k,int mod){
        int ans=1;
        while(k){
            if(k&1) ans=1ll*ans*p%mod;
            k>>=1ll,p=1ll*p*p%mod;
        }
        return ans;
    }
    /*

        & fast number theory transform .

        -> obvious .

        -> T(n) = O(n) + 2 * T( n / 2 ) = O( n*log(n) )

    */
   void ntt(int *a,int n,int flag){
        for(int i=0,j=0;i<n;i++){
            if(i>j) std::swap(a[i],a[j]);
            for(int t=n>>1;(j^=t)<t;t>>=1);
        }
        int w,wn,u,t;
        for(int m=2;m<=n;m<<=1){
            wn=ksm(G,flag==1?(P-1)/m:(P-1-(P-1)/m),P),w=1ll;
            for(int i=0;i<n;i+=m,w=1ll) for(int k=0,p=m>>1;k<p;k++,w=1ll*w*wn%P)
                t=1ll*w*a[i+k+p]%P,u=a[i+k],a[i+k]=(u+t)%P,a[i+k+p]=(u-t)%P;
        }
        if(flag==-1){
            int inv=ksm(n,P-2,P);
            for(int i=0;i<n;i++) a[i]=1ll*a[i]*inv%P;
        }
        return;
    }
    /*

        &polynomial derivative

        -> obvious .

        -> T(n) = O(n)

    */
    void poly_derivative(int *poly,int *der,int n){
        poly[n]=0;
        for(int i=0;i<n;i++) der[i]=1ll*(i+1)*poly[i+1]%P;
        return;
    }
    /*

        &polynomial integrate

        -> obvious .

        -> T(n) = O(n)

    */
    void poly_integrate(int *poly,int n){
        static int tmp[maxn];tmp[0]=0;
        for(int i=0;i<n;i++) tmp[i+1]=1ll*poly[i]*ksm(i+1,P-2,P)%P;
        for(int i=0;i<n;i++) poly[i]=(tmp[i]%P+P)%P;
        return;
    }
    /*

        & polynomial inverse

        -> G(x) * F(x) = 1 ( mod x^n )
        -> H(x) * F(x) = 1 ( mod x^2n )

        -> we want to know -> H(x)

        -> G(x) * F(x) - 1 =0 ( mod x^n )
        -> [G(x) * F(x) - 1] ^ 2 = 0 ( mod x^2n )
        -> [G(x)F(x)] ^ 2 - 2 * G(x) * F(x) + 1 = 0 ( mod x^2n )
        -> G(x) ^ 2 * F(x) - 2 * G(x) + H(x) = 0 ( mod x^2n )
        -> H(x) = 2 * G(x) - G(x) ^ 2 * F(x)

        -> H(x) = G(x) * [ 2 - G(x) * F(x) ]

        -> T(n) = O( n*log(n) ) + T( n / 2 ) = O( n*log(n) )

    */
    void poly_inverse(int *f,int *g,int n){
        static int tmp[maxn];
        if(n==1){g[0]=ksm(f[0],P-2,P);return;}
        poly_inverse(f,g,n>>1);
        memcpy(tmp,f,sizeof(f[0])*n);
        memset(tmp+n,0,sizeof(f[0])*n);
        ntt(tmp,n<<1,1),ntt(g,n<<1,1);
        for(int i=0;i<(n<<1);i++) tmp[i]=1ll*g[i]*(2ll-1ll*g[i]*tmp[i]%P)%P;
        ntt(tmp,n<<1,-1);
        for(int i=0;i<n;i++) g[i]=tmp[i];
        memset(g+n,0,sizeof(g[0])*n);
        return;
    }
    /*

        & polynomial sqrt

        ->   G(x) ^ 2 = F(x) ( mod x^n )
        ->   H(x) ^ 2 = F(x) ( mod x^2n )

        ->   we want to know -> H(x)

        ->   G(x) ^ 2 - F(x) = 0 ( mod x^n )
        ->   [ G(x) ^ 2 - F(x) ] ^ 2 = 0 ( mod x^2n )
        ->   [ G(x) ^ 2 + F(x) ] ^ 2 = 4 * ( G(x) ^ 2 ) * F(x) ( mod x^2n )
        ->   [ (G(x) ^ 2 + F(x)) / ( 2 * G(x) ) ] ^ 2 = F(x) ( mod x^2n )

        ->   H(x) = (G(x) ^ 2 + F(x)) / ( 2 * G(x) )

        -> T(n) = O( n*log(n) ) + T( n / 2 ) = O( n*log(n) )

    */
    void poly_sqrt(int *f,int *g,int n){
        static int tmp[maxn],ginv[maxn];
        if(n==1){g[0]=(int)sqrt(f[0]);return;}
        int inv2=ksm(2,P-2,P);
        poly_sqrt(f,g,n>>1);
        memset(ginv,0,sizeof(ginv[0])*n);
        poly_inverse(g,ginv,n);
        memcpy(tmp,f,sizeof(f[0])*n);
        memset(tmp+n,0,sizeof(f[0])*n);
        ntt(tmp,n<<1,1),ntt(g,n<<1,1),ntt(ginv,n<<1,1);
        for(int i=0;i<(n<<1);i++) tmp[i]=1ll*inv2*(g[i]+1ll*tmp[i]*ginv[i]%P)%P;
        ntt(tmp,n<<1,-1);
        for(int i=0;i<n;i++) g[i]=tmp[i];
        memset(g+n,0,sizeof(g[0])*n);
        return;
    }
    /*

        & polynomial ln

        ->   F(x) = ln ( G(x) )
        ->   F'(x) = G'(x) / G(x)

        ->   F(x) = ∫( G'(x) / G(x) ) dx

        -> T(n) = O( n*log(n) ) + O(n) = O( n*log(n) )

    */
    void poly_ln(int *poly,int *ln,int n){
        static int der[maxn],inv[maxn];
        memset(inv,0,sizeof(inv[0])*(n<<1));
        memset(der,0,sizeof(der[0])*(n<<1));
        poly_inverse(poly,inv,n);
        poly_derivative(poly,der,n);
        ntt(der,n<<1,1),ntt(inv,n<<1,1);
        for(int i=0;i<(n<<1);i++)
            ln[i]=1ll*der[i]*inv[i]%P;
        ntt(ln,n<<1,-1);
        poly_integrate(ln,n);
        memset(ln+n,0,sizeof(ln[0])*n);
        memset(inv,0,sizeof(inv[0])*(n<<1));
        memset(der,0,sizeof(der[0])*(n<<1));
        return;
    }
    /*

        & polynomial exp

        -> F(x) = e ^ A(x)
        -> G( F(x) ) = ln( F(x) ) - A(x) = 0

        -> Newton Iteration.
        -> F0(x) under ( mod x ^ n )
        -> F(x) under ( mod x ^ (2n) )
        -> F(x) = F0(x) - ( ln( F0(x) ) - A(x) ) / ( 1 / F0(x) )

        -> F(x) = F0(x)( 1 - ln( F0(x) ) + A(x) ) ( mod x ^ (2n) )

        -> T(n) = O( n*log(n) ) + T( n / 2 ) = O( n*log(n) )

    */
    void poly_exp(int *poly,int *exp,int n){
        static int tmp[maxn];
        if(n==1){exp[0]=1;return;}
        poly_exp(poly,exp,n>>1);
        memset(tmp,0,sizeof(tmp[0])*n<<1);
        poly_ln(exp,tmp,n);
        for(int i=0;i<n;i++) tmp[i]=((i==0)+P-tmp[i]+poly[i])%P;
        ntt(tmp,n<<1,1),ntt(exp,n<<1,1);
        for(int i=0;i<(n<<1);i++) exp[i]=1ll*exp[i]*tmp[i]%P;
        ntt(exp,n<<1,-1);
        for(int i=0;i<n;i++) ((exp[i]%=P)+=P)%=P;
        memset(exp+n,0,sizeof(exp[0])*n);
        return;
    }
    /*

        & polynomial power

        -> F(x) ^ k ( mod x ^ n ) = exp ( k * ln( F(x) ) )

        -> T(n) = O( n*log(n) )

    */
    void poly_pow(int *poly,int n,int k){
        static int ln[maxn],exp[maxn];
        poly_ln(poly,ln,n);
        for(int i=0;i<n;i++) poly[i]=1ll*k*ln[i]%P;
        poly_exp(poly,exp,n);
        for(int i=0;i<n;i++) poly[i]=exp[i];
        return;
    }
    /*

        &primitive_root

        -> ord(m,a) = phi(m)
        -> a is the primitive root of m
            * if not :
                exist-> a ^ i = a ^ j ( mod p )
                -> a ^ ( i - j ) = 1 ( mod p )
                -> i - j < ord(m,a)
                -> it contradicts the assumption .

        -> judge x is the primitive_root of m
            phi(m) = PI( pi ^ ai )
            * if exist x ^ ( phi(m) / pi ) = 1 ( mod m )
                x is not a primitive_root of m
                *if is -> x ^ ( phi(m) / pi ) = 1 ( mod p )
                    -> ord(m,x) = n , n | phi(m)
                        * if n < phi(m)
                            exist pi ->  n | ( phi(m) / pi )
                            -> x ^ ( phi(m) / pi ) = 1
                            -> x ^ n = 1
                            -> x ^ ( n - phi(m) / pi ) = 1
                            -> n - phi(m) / pi < n
                            -> it contradicts the assumption .

    */
    bool primitive_root_judge(int x,int p){
        for(int i=2;i*i<=p;i++) if((p-1)%i==0&&ksm(x,(p-1)/i,p)==1)
            return false;
        return true;
    }
    int primitive_root(int p){
        if(p==2) return 1;
        int ans=2;
        for(;!primitive_root_judge(ans,p);++ans);
        return ans;
    }
}

void read(int &x){
    x=0;int c=getchar();
    while(c<'0'||c>'9') c=getchar();
    for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    return;
}

int n,k,len,F[maxn],sqrtF[maxn],lnv_sqrt[maxn],exp_[maxn],inv2[maxn],ln2[maxn],G_[maxn];

int main(){
	freopen("polynomial.in","r",stdin);
	freopen("polynomial.out","w",stdout);
	G=polynomial::primitive_root(P);
	read(n),read(k);
	for(int i=0;i<n;i++) read(F[i]);
	for(len=1;len<=n;len<<=1);
	polynomial::poly_sqrt(F,sqrtF,len);
	polynomial::poly_inverse(sqrtF,lnv_sqrt,len);
	polynomial::poly_integrate(lnv_sqrt,len);
	polynomial::poly_exp(lnv_sqrt,exp_,len);
	polynomial::poly_inverse(exp_,inv2,len);
	(inv2[0]+=1)%=P;
	polynomial::poly_ln(inv2,ln2,len);
	(ln2[0]+=1)%=P;
	polynomial::poly_pow(ln2,len,k);
	polynomial::poly_derivative(ln2,G_,n);
	for(int i=0;i<n;i++) printf("%d ",(G_[i]%P+P)%P);
    return 0;
}