zoukankan      html  css  js  c++  java
  • 多项式乘法逆

    对于一个多项式 (F(x)),满足 (F(x)*G(x)equiv 1;(mod;x^n))(G) 就叫做 (F) 的乘法逆。

    如果只有一项,那么 (G_0) 就是 (F_0) 的逆元。

    若有多项,考虑倍增。

    假设已知 (H(x)) 使得 (F(x)*H(x) equiv 1;(mod;x^{left lceil frac{n}{2} ight ceil}))
    且显然 (F(x)*G(x) equiv 1;(mod;x^{left lceil frac{n}{2} ight ceil}))
    所以 (F(x)*(G(x)-H(x)) equiv 0;(mod;x^{left lceil frac{n}{2} ight ceil}))
    ((G(x)-H(x) equiv 0;(mod;x^{left lceil frac{n}{2} ight ceil}))

    那么设 (T(x)=(G(x)-H(x))^2),则

    [T_i=sum_{j=0}^{i}(G(x)-H(x))_{j}×(G(x)-H(x))_{i-j} ]

    因为 (G(x)-H(x) equiv 0;(mod;x^{left lceil frac{n}{2} ight ceil})) 那么 (G(x)-H(x))(0) 次项到 (left lceil frac{n}{2} ight ceil-1) 次项系数一定都为零,
    又因 ((G(x)-H(x))_j)((G(x)-H(x))_{i-j}) 中必有一项次数小于 (left lceil frac{n}{2} ight ceil)
    所以 (Tequiv 0;(mod;x^n))
    也就是 ((G(x)-H(x))^2equiv 0;(mod;x^n))

    两边同乘 (F),因为 (F(x)*G(x)equiv 1;(mod;x^n))
    所以化减得到 (G(x)equiv 2H(x)-F(x)*H(x)^2;(mod;x^n))

    (NTT) 即可,时间复杂度为 (mathcal O m(nlogn))

    Code
    #include<bits/stdc++.h>
    #define Re register
    #define ri Re signed
    #define pd(i) ++i
    #define bq(i) --i
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
        struct nanfeng_stream{
            template<typename T>inline nanfeng_stream &operator>>(T &x) {
                Re bool f=false;x=0;Re char ch=gc();
                while(!isdigit(ch)) f|=ch=='-',ch=gc();
                while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
                return x=f?-x:x,*this;
            }
        }cin;
    }
    using IO::cin;
    namespace nanfeng{
        #define FI FILE *IN
        #define FO FILE *OUT
        template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
        template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
        static const int N=1<<19,MOD=998244353;
        int a[N],b[N],c[N],w1[N],w2[N],R[N],n,len,st,inv;
        auto fpow=[](int x,int y) {
            int res=1;
            while(y) {
                if (y&1) res=1ll*res*x%MOD;
                x=1ll*x*x%MOD;
                y>>=1;
            }
            return res;
        };
        auto MD=[](int x) {return x>=MOD?x-MOD:x;};
        inline void NTT1(int *a) {
            for (ri i(0);i<st;pd(i)) if (R[i]>i) std::swap(a[R[i]],a[i]);
            for (ri t(st>>1),d(1);d<st;t>>=1,d<<=1)
                for (ri i(0);i<st;i+=d<<1)
                    for (ri j(0);j<d;pd(j)) {
                        const int tmp=1ll*w1[t*j]*a[i+j+d]%MOD;
                        a[i+j+d]=(a[i+j]-tmp+MOD)%MOD;
                        a[i+j]=MD(a[i+j]+tmp);
                    }
        }
        inline void NTT2(int *a) {
            for (ri i(0);i<st;pd(i)) if (R[i]>i) std::swap(a[R[i]],a[i]);
            for (ri t(st>>1),d(1);d<st;t>>=1,d<<=1)
                for (ri i(0);i<st;i+=d<<1)
                    for (ri j(0);j<d;pd(j)) {
                        const int tmp=1ll*w2[t*j]*a[i+j+d]%MOD;
                        a[i+j+d]=(a[i+j]-tmp+MOD)%MOD;
                        a[i+j]=MD(a[i+j]+tmp);
                    }
            for (ri i(0);i<st;pd(i)) a[i]=1ll*a[i]*inv%MOD;
        }
        void calc(int deg) {
            if (deg==1) return (void)(b[0]=fpow(a[0],MOD-2));
            calc(deg+1>>1);
            len=0,st=1;
            while(st<=deg<<1) st<<=1,++len;
            inv=fpow(st,MOD-2);
            w1[1]=fpow(3,(MOD-1)/st);
            w2[1]=fpow(w1[1],MOD-2);
            for (ri i(2);i<st;pd(i)) 
                w1[i]=1ll*w1[i-1]*w1[1]%MOD,w2[i]=1ll*w2[i-1]*w2[1]%MOD;
            for (ri i(0);i<st;pd(i)) R[i]=(R[i>>1]>>1)|((i&1)<<(len-1));
            memcpy(c,a,sizeof(int)*deg);
            memset(c+deg,0,sizeof(int)*(st-deg));
            NTT1(b),NTT1(c);
            for (ri i(0);i<st;pd(i)) b[i]=1ll*(2ll-1ll*b[i]*c[i]%MOD+MOD)%MOD*b[i]%MOD;
            NTT2(b);
            memset(b+deg,0,sizeof(int)*(st-deg));
        }
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            w1[0]=w2[0]=1;
            cin >> n;
            for (ri i(0);i<n;pd(i)) cin >> a[i];
            calc(n);
            for (ri i(0);i<n;pd(i)) printf("%d ",b[i]);
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    
  • 相关阅读:
    hdu 1087(LIS变形)
    poj 1088(记忆化搜索)
    hdu 1505(最大子矩阵)
    hdu 1506(好题+DP或者RMQ)
    poj 2593&&poj2479(最大两子段和)
    hdu 1003(最大子段和)
    hdu 2881(LIS变形)
    poj 1692(动态规划)
    CodeForces 626C Block Towers
    CodeForces 626B Cards
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15256236.html
Copyright © 2011-2022 走看看