ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

多项式乘法逆

2021-09-11 17:33:04  阅读:164  来源: 互联网

标签:lceil right frac 多项式 bmod 乘法 rceil equiv


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

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

若有多项,考虑倍增。

假设已知 \(H(x)\) 使得 \(F(x)*H(x) \equiv 1\;(\bmod\;x^{\left \lceil \frac{n}{2} \right \rceil})\),
且显然 \(F(x)*G(x) \equiv 1\;(\bmod\;x^{\left \lceil \frac{n}{2} \right \rceil})\),
所以 \(F(x)*(G(x)-H(x)) \equiv 0\;(\bmod\;x^{\left \lceil \frac{n}{2} \right \rceil})\),
即 \((G(x)-H(x) \equiv 0\;(\bmod\;x^{\left \lceil \frac{n}{2} \right \rceil})\)。

那么设 \(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\;(\bmod\;x^{\left \lceil \frac{n}{2} \right \rceil})\) 那么 \(G(x)-H(x)\) 在 \(0\) 次项到 \(\left \lceil \frac{n}{2} \right \rceil-1\) 次项系数一定都为零,
又因 \((G(x)-H(x))_j\),\((G(x)-H(x))_{i-j}\) 中必有一项次数小于 \(\left \lceil \frac{n}{2} \right \rceil\),
所以 \(T\equiv 0\;(\bmod\;x^n)\),
也就是 \((G(x)-H(x))^2\equiv 0\;(\bmod\;x^n)\)。

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

用 \(NTT\) 即可,时间复杂度为 \(\mathcal O\rm(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();}

标签:lceil,right,frac,多项式,bmod,乘法,rceil,equiv
来源: https://www.cnblogs.com/nanfeng-blog/p/15256236.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有