zoukankan      html  css  js  c++  java
  • 多项式运算

    多项式运算

    前置知识NTT

    所有操作均在对(P= ext{998244353})取模下进行

    代码在最下面,由于板子实在有一点长,所以。。。

    下文中(pmod {x^n})表示求出了多项式的前(n)

    ([x^i]F(x))表示(F(x))(i)项的系数

    每个小问题的模板题都可以在洛谷上找到


    [ ]

    1.多项式求乘法逆

    (为什么叫做乘法逆?因为还有求(G(x)=frac{1}{F(x)}pmod {M(x)}的))

    (G(x)equiv frac{1}{F(x)} pmod {x^n})

    形象化的理解就是(F(x)cdot G(x) pmod {x^n})只有第一项是(1),其他项都是(0)

    这个由于是第一个操作,很多人还并不是很能理解多项式操作到底是什么东西,所以讲多一点

    Part1 O((n^2))

    为了便于理解这个问题,先考虑一个最简单的模拟

    ([x^i]Fcdot G(x)=sum [x^j]F(x)[x^{i-j}]G(x))

    第一项([x^0]G(x)=frac{1}{[x^0]F(0)} pmod P),因此求逆的前提条件是([x^0]F(x) e 0)

    考虑从(1)(n-1)依次求出每一项,先从前面的项中得到所有(j>0)的和(Sum),然后带入(j=0)时知道

    [[x^i]G(x)=-frac{Sum=sum_{j=1}^{jleq i}[x^j]F(x)[x^{i-j}]G(x)}{[x^0]F(0)} ]

    [ ]


    Part2 O((nlog^2n))

    上面这个式子是一个类似(dp)转移的东西,可以直接分治NTT优化掉

    [ ]


    Part3 (O(nlog n))

    考虑递归求解,设已经求出了

    [H(x)equiv frac{1}{F(x)},pmod {x^{frac{n}{2}}} ]

    其中递归边界是(n=1)时,([x^0]G(x)=frac{1}{[x^0]F(0)} pmod P),因此求逆的前提条件是([x^0]F(x) e 0)

    [H(x)equiv G(x)pmod {x^{frac{n}{2}}} ]

    [H(x)-G(x)equiv 0pmod {x^{frac{n}{2}}} ]

    我们对于(H(x)-G(x))平方,结果的前(n)项不可能由两个(ge frac{n}{2})的项相乘得到,而前(frac{n}{2})项都是(0),所以

    [(H(x)-G(x))^2equiv 0pmod {x^n} ]

    所以通过平方可以扩大模数,这很常用

    展开平方的式子

    [H(x)^2-2G(x)H(x)+G(x)^2equiv 0pmod {x^n} ]

    两边乘上(F(x))

    [H(x)^2F(x)-2H(x)+G(x)equiv 0pmod {x^n} ]

    [G(x)equiv 2H(x)-H(x)^2F(x)pmod {x^n} ]

    带入这个式子倍增求解即可

    分析复杂度,每次有一个(H(x)^2F(x)),可以通过(NTT)求出,倍增过程中访问的长度是(O(n+frac{n}{2}+frac{n}{4}...)=O(n))

    所以总复杂度就是(O(nlog n))

    [ ]


    2.多项式开根号

    (G(x)^2equiv F(x) pmod {x^n})

    同样的,递归求解,设已经求出了,递归边界是(n=1)时,([x^0]G(x)=sqrt{[x^0]F(x)}pmod P)

    可以发现我们需要求二次剩余。。。但是一般题目保证了([x^0]F(x)in{0,1})

    设已经求出(H(x)^2equiv F(x) pmod{ x^{lceil frac{n}{2} ceil}})

    [H(x)equiv G(x) pmod {x^{lceil frac{n}{2} ceil}} ]

    [H(x)^2-2G(x)H(x)+G(x)^2equiv 0pmod {x^n} ]

    [H(x)^2-2G(x)H(x)+F(x)equiv 0 pmod {x^n} ]

    [G(x)equiv frac{H(x)^2+F(x)}{2H(x)} pmod {x^n} ]

    带入这个式子倍增求解即可

    复杂度为(O(nlog n))

    [ ]


    3.多项式求(ln)

    对$egin{aligned} G(x)equiv ln F(x) pmod {x^n} end{aligned} $ 两边求导,注意这里是复合函数求导!!!

    (egin{aligned} G'(x)equiv F'(x)frac{1}{F(x)} pmod {x^n}end{aligned})

    求出(G'(x)),然后求原函数即可

    复杂度为(O(nlog n))

    [ ]


    4.多项式求exp

    多项式求( ext{exp})即求(G(x)=e^{F(x)} mod x^n)

    多项式求( ext{exp})常见的解法有两种

    CDQ分治+( ext{NTT})

    要求(G(x)=e^{F(x)})

    式子两边求导(右边要复合函数求导),(G'(x)=F'(x) e^{F(x)})

    也就是说,(G'(x)=F'(x)G(x))

    两边同时积分得到(egin{aligned} G(x)=int{F'(x)G(x)}end{aligned})

    我们知道,$ [x^i] egin{aligned}int H(x) =frac{ [x^{i-1}]H(x)}{i}end{aligned} $

    带入上面的式子得到([x^i]G(x)=frac{sum_{j=0}^{i-1}[x^j]F'(x)cdot [x^{i-1-j}]G(x)}{i})

    那么对于这个式子,直接使用分治NTT求解,其复杂为(O(nlog^2 n))

    [ ]

    牛顿迭代

    这是一种渐进意义上更优的做法,但实际在(10^6)以下几乎不可能更快,而且代码难写

    但是不管平时用不用,牛顿迭代的知识学习一下肯定是最好的

    把题目转化为,对于函数(f(G)=ln G-F)

    求出在(mod x^n)意义下的零点

    其中(f(x)=ln x-c)

    考虑迭代求解,设已经求出(H(x)=e^{F(x)}pmod {x^{frac{n}{2}}})

    边界条件是([x^0]H(x)=e^{[x^0]F(x)})(由于没有办法求(e^x)在模意义下的值,所以通常必须要满足([x^0]F(x)=0))

    带入牛顿迭代的结果

    [G=H-frac{f(H)}{f'(H)}=H(F-ln H+1) ]

    每次求(ln) 复杂度和( ext{NTT})相同,所以总复杂度为(O(nlog n))

    事实上这个还有优化的余地,就是在求(ln)的时候,多项式逆的部分可以同步倍增求出,不需要每次都倍增一下(但是好像效果并不是特别明显)

    [ ]

    [ ]


    5.多项式(k)次幂

    (G(x)equiv F(x)^kpmod {x^n})

    (ln G(x)=k ln F(x) pmod {x^n})

    求出(ln G(x))之后,(exp)回来即可

    由于要求(ln),所以这样求的条件是([x^0]F(x)=1)

    很显然这个方法对于开根号也是适用的

    复杂度(O(nlog n))

    [ ]

    [ ]

    [ ]


    6.多项式带余除法

    可以参考神仙miskcoo的博客

    应用:多项式多点求值常系数线性齐次递推

    [ ]

    以上是基本运算,如果不想继续吸多项式请直接跳到最下面的代码

    多项式与点值式

    下降幂多项式初步

    [ ]

    [ ]


    [ ]

    [ ]

    [ ]


    所有的操作均用$ ext{vector} $来实现,主要是为了理清思路,并且清零问题上会比较容易解决,同时对于每次计算完多项式的长度的要求会显得更加严格


    稍微整理了一下,没怎么卡过常,所以应该还是比较可读的

    代码总览(请使用C++11,O2编译运行)

    基本运算的总模板题Loj - 150

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef double db;
    typedef unsigned long long ull;
    typedef pair <int,int> Pii;
    #define reg register
    #define pb push_back
    #define mp make_pair
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    template <class T=int> T rd(){
        T s=0; int f=0;
        while(!isdigit(IO=getchar())) if(IO=='-') f=1;
        do s=(s<<1)+(s<<3)+(IO^'0');
        while(isdigit(IO=getchar()));
        return f?-s:s;
    }
    
    const int N=1<<17,P=998244353;
    
    int n,k;
    
    ll qpow(ll x,ll k=P-2) {
        ll res=1;
        for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
        return res;
    }
    
    /*
    void NTT(int n,int *a,int f){
        rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(int i=1;i<n;i<<=1) {
            int w=qpow(3,(P-1)/i/2);
            for(int l=0;l<n;l+=i*2) {
                int e=1;
                for(int j=l;j<l+i;++j,e=1ll*e*w%P) {
                    int t=1ll*a[j+i]*e%P;
                    a[j+i]=a[j]-t,((a[j+i]<0)&&(a[j+i]+=P));
                    a[j]+=t,((a[j]>=P)&&(a[j]-=P));
                }
            }
        }
        if(f==-1) {
            reverse(a+1,a+n);
            int Inv=qpow(n);
            rep(i,0,n-1) a[i]=1ll*a[i]*Inv%P;
        }
    }
    
    int e[N];
    void NTT(int n,int *a,int f){
        rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        e[0]=1;
        for(int i=1;i<n;i<<=1) {
            int w=qpow(3,(P-1)/i/2);
            for(int j=1;j<i;++j) e[j]=1ll*e[j-1]*w%P;
            for(int l=0;l<n;l+=i*2) {
                for(int j=l;j<l+i;++j) {
                    int t=1ll*a[j+i]*e[j-l]%P;
                    a[j+i]=a[j]-t,((a[j+i]<0)&&(a[j+i]+=P));
                    a[j]+=t,((a[j]>=P)&&(a[j]-=P));
                }
            }
        }
        if(f==-1) {
            reverse(a+1,a+n);
            int Inv=qpow(n);
            rep(i,0,n-1) a[i]=1ll*a[i]*Inv%P;
        }
    }
    
    int e[N];
    void NTT(int n,int *a,int f){
        rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        e[0]=1;
        for(int i=1;i<n;i<<=1) {
            int w=qpow(3,(P-1)/i/2);
            for(int j=i-2;j>=0;j-=2) e[j+1]=1ll*w*(e[j]=e[j>>1])%P;
            for(int l=0;l<n;l+=i*2) {
                for(int j=l;j<l+i;++j) {
                    int t=1ll*a[j+i]*e[j-l]%P;
                    a[j+i]=a[j]-t,((a[j+i]<0)&&(a[j+i]+=P));
                    a[j]+=t,((a[j]>=P)&&(a[j]-=P));
                }
            }
        }
        if(f==-1) {
            reverse(a+1,a+n);
            int Inv=qpow(n);
            rep(i,0,n-1) a[i]=1ll*a[i]*Inv%P;
        }
    }
    
    int w[N];
    void Init(int N){
        w[N>>1]=1;
        int t=qpow(3,(P-1)/N);
        rep(i,(N>>1)+1,N-1) w[i]=1ll*w[i-1]*t%P;
        drep(i,(N>>1)-1,1) w[i]=w[i<<1];
    }
    void NTT(int n,int *a,int f){
        rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(int i=1;i<n;i<<=1) {
            int *e=w+i;
            for(int l=0;l<n;l+=i*2) {
                for(int j=l;j<l+i;++j) {
                    int t=1ll*a[j+i]*e[j-l]%P;
                    a[j+i]=a[j]-t,((a[j+i]<0)&&(a[j+i]+=P));
                    a[j]+=t,((a[j]>=P)&&(a[j]-=P));
                }
            }
        }
        if(f==-1) {
            reverse(a+1,a+n);
            int Inv=qpow(n);
            rep(i,0,n-1) a[i]=1ll*a[i]*Inv%P;
        }
    }
    */
    
    /*
    namespace MTT{
        const double PI=acos((double)-1);
        int rev[N];
        struct Cp{
            double x,y;
            Cp(){ ; }
            Cp(double _x,double _y): x(_x),y(_y){ } 
            inline Cp operator + (const Cp &t) const { return (Cp){x+t.x,y+t.y}; }
            inline Cp operator - (const Cp &t) const { return (Cp){x-t.x,y-t.y}; }
            inline Cp operator * (const Cp &t) const { return (Cp){x*t.x-y*t.y,x*t.y+y*t.x}; }
        }A[N],B[N],C[N],w[N/2];
    #define E(x) ll(x+0.5)%P
        void FFT(int n,Cp *a,int f){
            rep(i,0,n-1) if(rev[i]<i) swap(a[i],a[rev[i]]);
            w[0]=Cp(1,0);
            for(reg int i=1;i<n;i<<=1) {
                Cp t=Cp(cos(PI/i),f*sin(PI/i));
                for(reg int j=i-2;j>=0;j-=2) w[j+1]=t*(w[j]=w[j>>1]);
                // 上面提到的最优板子
                for(reg int l=0;l<n;l+=2*i) {
                    for(reg int j=l;j<l+i;j++) {
                        Cp t=a[j+i]*w[j-l];
                        a[j+i]=a[j]-t;
                        a[j]=a[j]+t;
                    }
                }
            }
            if(f==-1) rep(i,0,n-1) a[i].x/=n,a[i].y/=n;
        }
        void Multiply(int n,int m,int *a,int *b,int *res,int P){
            // [0,n-1]*[0,m-1]->[0,n+m-2]
            int S=(1<<15)-1;
            int R=1,cc=-1;
            while(R<=n+m-1) R<<=1,cc++;
            rep(i,1,R) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
            rep(i,0,n-1) A[i]=Cp((a[i]&S),(a[i]>>15));
            rep(i,0,m-1) B[i]=Cp((b[i]&S),(b[i]>>15));
            rep(i,n,R-1) A[i]=Cp(0,0);
            rep(i,m,R-1) B[i]=Cp(0,0);
            FFT(R,A,1),FFT(R,B,1);
            rep(i,0,R-1) {
                int j=(R-i)%R;
                C[i]=Cp((A[i].x+A[j].x)/2,(A[i].y-A[j].y)/2)*B[i];
                B[i]=Cp((A[i].y+A[j].y)/2,(A[j].x-A[i].x)/2)*B[i];
            }
            FFT(R,C,-1),FFT(R,B,-1);
            rep(i,0,n+m-2) {
                ll a=E(C[i].x),b=E(C[i].y),c=E(B[i].x),d=E(B[i].y);
                res[i]=(a+((b+c)<<15)+(d<<30))%P;
            }
        }
    #undef E
    }
    */
    
    
    namespace Polynomial{
    
        typedef vector <int> Poly;
        void Show(Poly a,int k=0){ 
            if(!k){ for(int i:a) printf("%d ",i); puts(""); }
            else for(int i:a) printf("%d
    ",i);
        }
        int rev[N],w[N];
        int Inv[N+1],Fac[N+1],FInv[N+1];
    
        void Init_w() { 
            int t=qpow(3,(P-1)/N);
            w[N>>1]=1;
            rep(i,(N>>1)+1,N-1) w[i]=1ll*w[i-1]*t%P;
            drep(i,(N>>1)-1,1) w[i]=w[i<<1];
            Inv[0]=Inv[1]=Fac[0]=Fac[1]=FInv[0]=FInv[1]=1;
            rep(i,2,N) {
                Inv[i]=1ll*(P-P/i)*Inv[P%i]%P; 
                FInv[i]=1ll*FInv[i-1]*Inv[i]%P;
                Fac[i]=1ll*Fac[i-1]*i%P;
            }
        }
        int Init(int n){
            int R=1,c=-1;
            while(R<n) R<<=1,c++;
            rep(i,1,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<c);
            return R;
        }
    
    #define NTTVersion1
    
    #ifdef NTTVersion1
        void NTT(int n,Poly &a,int f){
            rep(i,0,n-1) if(rev[i]<i) swap(a[i],a[rev[i]]);
            for(int i=1;i<n;i<<=1) {
                int *e=w+i;
                for(int l=0;l<n;l+=i*2) {
                    for(int j=l;j<l+i;++j) {
                        int t=1ll*a[j+i]*e[j-l]%P;
                        a[j+i]=a[j]-t,Mod2(a[j+i]);
                        a[j]+=t,Mod1(a[j]);
                    }
                }
            }
            if(f==-1) {
                reverse(a.begin()+1,a.begin()+n);
                ll base=Inv[n];
                rep(i,0,n-1) a[i]=a[i]*base%P;
            }
        }
        void NTT(int n,int *a,int f){
            rep(i,0,n-1) if(rev[i]<i) swap(a[i],a[rev[i]]);
            for(int i=1;i<n;i<<=1) {
                int *e=w+i;
                for(int l=0;l<n;l+=i*2) {
                    for(int j=l;j<l+i;++j) {
                        int t=1ll*a[j+i]*e[j-l]%P;
                        a[j+i]=a[j]-t,Mod2(a[j+i]);
                        a[j]+=t,Mod1(a[j]);
                    }
                }
            }
            if(f==-1) {
                reverse(a+1,a+n);
                ll base=Inv[n];
                rep(i,0,n-1) a[i]=a[i]*base%P;
            }
        }
    
    #else 
    
        void NTT(int n,Poly &a,int f){ 
            static int e[N>>1];
            rep(i,0,n-1) if(rev[i]<i) swap(a[i],a[rev[i]]);
            e[0]=1;
            for(int i=1;i<n;i<<=1) {
                int t=qpow(f==1?3:(P+1)/3,(P-1)/i/2);
                for(int j=i-2;j>=0;j-=2) e[j+1]=1ll*t*(e[j]=e[j>>1])%P;
                for(int l=0;l<n;l+=i*2) {
                    for(int j=l;j<l+i;++j) {
                        int t=1ll*a[j+i]*e[j-l]%P;
                        a[j+i]=a[j]-t,Mod2(a[j+i]);
                        a[j]+=t,Mod1(a[j]);
                    }
                }
            }
            if(f==-1) {
                ll base=Inv[n];
                rep(i,0,n-1) a[i]=a[i]*base%P;
            }
        }
        void NTT(int n,int *a,int f){ 
            static int e[N>>1];
            rep(i,0,n-1) if(rev[i]<i) swap(a[i],a[rev[i]]);
            e[0]=1;
            for(int i=1;i<n;i<<=1) {
                int t=qpow(f==1?3:(P+1)/3,(P-1)/i/2);
                for(int j=i-2;j>=0;j-=2) e[j+1]=1ll*t*(e[j]=e[j>>1])%P;
                for(int l=0;l<n;l+=i*2) {
                    for(int j=l;j<l+i;++j) {
                        int t=1ll*a[j+i]*e[j-l]%P;
                        a[j+i]=a[j]-t,Mod2(a[j+i]);
                        a[j]+=t,Mod1(a[j]);
                    }
                }
            }
            if(f==-1) {
                ll base=Inv[n];
                rep(i,0,n-1) a[i]=a[i]*base%P;
            }
        }
    
    #endif
    
    
        Poly operator * (Poly a,Poly b){
            int n=a.size()+b.size()-1;
            int R=Init(n);
            a.resize(R),b.resize(R);
            NTT(R,a,1),NTT(R,b,1);
            rep(i,0,R-1) a[i]=1ll*a[i]*b[i]%P;
            NTT(R,a,-1);
            a.resize(n);
            return a;
        }
    
        Poly operator + (Poly a,Poly b) { 
            int n=max(a.size(),b.size());
            a.resize(n),b.resize(n);
            rep(i,0,n-1) a[i]+=b[i],Mod1(a[i]);
            return a; 
        }
        Poly operator - (Poly a,Poly b) { 
            int n=max(a.size(),b.size());
            a.resize(n),b.resize(n);
            rep(i,0,n-1) a[i]-=b[i],Mod2(a[i]);
            return a; 
        }
    
        Poly Poly_Inv(Poly a) { // 多项式乘法逆,注意这里求出的是前a.size()项
            int n=a.size();
            if(n==1) return Poly{(int)qpow(a[0],P-2)};
            Poly b=a; b.resize((n+1)/2); b=Poly_Inv(b);
            int R=Init(n<<1);
            a.resize(R),b.resize(R);
            NTT(R,a,1),NTT(R,b,1);
            rep(i,0,R-1) a[i]=(2-1ll*a[i]*b[i]%P+P)*b[i]%P;
            NTT(R,a,-1);
            a.resize(n);
            return a;
        }
    
        Poly operator / (Poly a,Poly b){ // 多项式带余除法
            reverse(a.begin(),a.end()),reverse(b.begin(),b.end());
            int n=a.size(),m=b.size();
            a.resize(n-m+1),b.resize(n-m+1),b=Poly_Inv(b);
            a=a*b,a.resize(n-m+1);
            reverse(a.begin(),a.end());
            return a;
        }
        Poly operator % (Poly a,Poly b) { // 多项式取模
            int n=b.size()-1;
            if((int)a.size()<=n) return a;
            Poly t=a/b;
            if((int)t.size()>n) t.resize(n);
            t=t*b; t.resize(n); a.resize(n);
            return a-t;
        }
    
        int Quad(int a,int k=0) { // 二次剩余(不是原根法),用于求Sqrt
            if(a<=1) return a;
            ll x;
            while(1) {
                x=1ll*rand()*rand()%P;
                if(qpow((x*x-a+P)%P,(P-1)/2)!=1) break;
            }
            ll w=(x*x-a+P)%P;
            Pii res=mp(1,0),t=mp(x,1);
            auto Mul=[&](Pii a,Pii b){
                int x=(1ll*a.first*b.first+1ll*a.second*b.second%P*w)%P,y=(1ll*a.first*b.second+1ll*a.second*b.first)%P;
                return mp(x,y);
            };
            int d=(P+1)/2;
            while(d) {
                if(d&1) res=Mul(res,t);
                t=Mul(t,t);
                d>>=1;
            }
            ll r=(res.first%P+P)%P;
            if(k) r=min(r,(P-r)%P);
            return r;
        }
        Poly Sqrt(Poly a){ // 多项式开根号
            int n=a.size();
            if(n==1) return Poly{Quad(a[0],1)};
            Poly b=a; b.resize((n+1)/2),b=Sqrt(b),b.resize(n);
            Poly c=Poly_Inv(b);
            int R=Init(n*2);
            a.resize(R),c.resize(R);
            NTT(R,a,1),NTT(R,c,1);
            rep(i,0,R-1) a[i]=1ll*a[i]*c[i]%P;
            NTT(R,a,-1);
            a.resize(n);
            rep(i,0,n-1) a[i]=1ll*(P+1)/2*(a[i]+b[i])%P;
            return a;
        }
    
        Poly Deri(Poly a){ //求导
            rep(i,1,a.size()-1) a[i-1]=1ll*i*a[i]%P;
            a.pop_back();
            return a;
        }
        Poly IDeri(Poly a) { //原函数
            a.pb(0);
            drep(i,a.size()-1,1) a[i]=1ll*a[i-1]*Inv[i]%P;
            a[0]=0;
            return a;
        }
    
        Poly Ln(Poly a){ // 多项式求Ln
            int n=a.size();
            a=Poly_Inv(a)*Deri(a),a.resize(n-1);
            return IDeri(a);
        }
        Poly Exp(Poly a){ // 多项式Exp
            int n=a.size();
            if(n==1) return Poly{1};
            Poly b=a; b.resize((n+1)/2),b=Exp(b); b.resize(n);
            Poly c=Ln(b);
            rep(i,0,n-1) c[i]=a[i]-c[i],Mod2(c[i]);
            c[0]++,b=b*c;
            b.resize(n);
            return b;
        }
    
        void Exp_Solve(Poly &A,Poly &B,int l,int r){
            static int X[N],Y[N];
            if(l==r) {
                B[l]=1ll*B[l]*Inv[l]%P;
                return;
            }
            int mid=(l+r)>>1;
            Exp_Solve(A,B,l,mid);
            int R=Init(r-l+2);
            rep(i,0,R) X[i]=Y[i]=0;
            rep(i,l,mid) X[i-l]=B[i];
            rep(i,0,r-l-1) Y[i+1]=A[i];
            NTT(R,X,1),NTT(R,Y,1);
            rep(i,0,R-1) X[i]=1ll*X[i]*Y[i]%P;
            NTT(R,X,-1);
            rep(i,mid+1,r) B[i]+=X[i-l],Mod1(B[i]);
            Exp_Solve(A,B,mid+1,r);
        }
        Poly CDQ_Exp(Poly F){
            int n=F.size(); F=Deri(F);
            Poly A(n);
            A[0]=1;
            Exp_Solve(F,A,0,n-1);
            return A;
        }
    
    
        Poly Pow(Poly x,int k) { // 多项式k次幂
            x=Ln(x);
            rep(i,0,x.size()-1) x[i]=1ll*x[i]*k%P;
            return Exp(x);
        }
    
        Poly EvaluateTemp[N<<1];
        void EvaluateSolve1(Poly &a,int l,int r,int p=1){
            if(l==r) { EvaluateTemp[p]=Poly{P-a[l],1}; return; } 
            int mid=(l+r)>>1;
            EvaluateSolve1(a,l,mid,p<<1),EvaluateSolve1(a,mid+1,r,p<<1|1);
            EvaluateTemp[p]=EvaluateTemp[p<<1]*EvaluateTemp[p<<1|1];
        }
        void EvaluateSolve2(Poly &res,Poly F,int l,int r,int p=1){
            if(l==r){ res[l]=F[0]; return; }
            int mid=(l+r)>>1;
            EvaluateSolve2(res,F%EvaluateTemp[p<<1],l,mid,p<<1);
            EvaluateSolve2(res,F%EvaluateTemp[p<<1|1],mid+1,r,p<<1|1);
        }
        Poly Evaluate(Poly a,Poly b,int flag=1){ // 多项式多点求值
            Poly res(b.size());
            if(flag) EvaluateSolve1(b,0,b.size()-1);
            EvaluateSolve2(res,a,0,b.size()-1);
            return res;
        }
        Poly InterpolationSolve(Poly &T,int l,int r,int p=1){ 
            if(l==r) return Poly{T[l]};
            int mid=(l+r)>>1;
            return InterpolationSolve(T,l,mid,p<<1)*EvaluateTemp[p<<1|1]+InterpolationSolve(T,mid+1,r,p<<1|1)*EvaluateTemp[p<<1];
        }
        Poly Interpolation(Poly X,Poly Y){ // 多项式快速插值
            int n=X.size();
            EvaluateSolve1(X,0,n-1);
            Poly T=Evaluate(Deri(EvaluateTemp[1]),X,0);
            rep(i,0,n-1) T[i]=Y[i]*qpow(T[i])%P;
            return InterpolationSolve(T,0,n-1);
        }
    
        void FFPTrans(Poly &a,int f){ // FFP<->EGF
            int n=a.size();
            Poly b(n);
            if(f==1) rep(i,0,n-1) b[i]=FInv[i];
            else rep(i,0,n-1) b[i]=(i&1)?P-FInv[i]:FInv[i];
            a=a*b; a.resize(n);
        }
        Poly FFPMul(Poly a,Poly b){ // FFP卷积
            int n=a.size()+b.size()-1;
            a.resize(n),b.resize(n);
            FFPTrans(a,1),FFPTrans(b,1);
            rep(i,0,n-1) a[i]=1ll*a[i]*b[i]%P*Fac[i]%P;
            FFPTrans(a,-1);
            return a;
        }
        Poly PolyToFFP(Poly F){ // 多项式转FFP
            int n=F.size();
            Poly G(n);
            rep(i,0,n-1) G[i]=i;
            G=Evaluate(F,G);
            rep(i,0,n-1) F[i]=1ll*G[i]*FInv[i]%P;
            FFPTrans(F,-1);
            return F;
        }
        Poly FFPToPoly(Poly F){ // FFP转多项式
            FFPTrans(F,1);
            int n=F.size(); Poly X(n);
            rep(i,0,n-1) X[i]=i,F[i]=1ll*F[i]*Fac[i]%P;
            EvaluateSolve1(X,0,n-1);
            rep(i,0,n-1) {
                F[i]=1ll*F[i]*FInv[i]%P*FInv[n-i-1]%P;
                if((n-i-1)&1) F[i]=(P-F[i])%P;
            }
            return InterpolationSolve(F,0,n-1);
        }
    }
    using namespace Polynomial;
    
    Poly Lag(int n,Poly X,Poly Y){
        Poly T(n+1),R(n+1),A(n+1);
        T[0]=1;
        rep(i,0,n) drep(j,i+1,0) T[j]=(1ll*T[j]*(P-X[i])+(j?T[j-1]:0))%P;
        rep(i,0,n) {
            ll t=1;
            rep(j,0,n) if(i!=j) t=t*(X[i]-X[j]+P)%P;
            t=qpow(t)*Y[i]%P,R[n+1]=T[n+1];
            drep(j,n,0) A[j]=(A[j]+t*R[j+1])%P,R[j]=(T[j]+1ll*R[j+1]*X[i]%P+P)%P;
        }
        return A;
    }
    
    int main(){
        int n=rd();
        Init_w();
        Poly F(n);
        rep(i,0,n-1) F[i]=rd();
        Show(CDQ_Exp(F));
    }
    
    
    
    
    
    

    [ ]

    [ ]

    [ ]

  • 相关阅读:
    Linux基础命令-cp
    Linux基础命令-mkdir
    Linux基础命令-touch
    Linux基础命令-diff
    Linux基础命令-cut
    Linux基础命令-stat
    System.Web.HttpException: 请求在此上下文中不可用
    数据库日志删除、压缩操作
    如何收缩和删除SQL日志文件
    Excel 常用宏代码大全
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12801809.html
Copyright © 2011-2022 走看看