码迷,mamicode.com
首页 > 其他好文 > 详细

【模板】多项式求逆

时间:2019-05-06 18:49:13      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:span   多项式   display   ons   std   const   mit   2-2   typedef   

蒟蒻写题解实在不易

前置芝士

多项式最高次数为度,多项式\(A\)的度记为:\(deg(A)\)

多项式取模的意义:将多项式\(A\)记作余式\(A(x)=Q(x)B(x)+R(x)\),则\(A(x)\equiv R(x)(mod B(x))\)

推式前置

  • \(F(x)G(x)\equiv 1 (mod~x^n)\)\(F(x)G(x)=Q(x)*x^n+1\)

  • 求逆的关键在于\(G(x)\)\(F(x)H(x)\equiv 1(mod~ x^{\lceil \frac{n}{2} \rceil})\)\(H(x)\)推过来

  • \(F(x)G(x)\equiv 1 (mod~x)\)则除常数项其他是会消掉的,\(F(x)\equiv f[0] (mod~x)\)\(\therefore G(x)=f[0]^{-1}\)

  • 那么\(G(x)\)\(H(x)\)有什么关系呢?先看一下\((mod~x^n)\)\((mod~ x^{\lceil \frac{n}{2} \rceil})(n>1)\)的关系:
    \[\begin{aligned}\F(x)G(x)&=Q*x^n+1\F(x)G(x)&=Q'*x^{\lceil \frac{n}{2} \rceil}+?\?=1:Q'&可以通过与Q的相乘次数差转换过来,所以余数为1\\end{aligned}\]

  • \(F(x)G(x)\equiv 1(mod~x)\longrightarrow F(x)G(x)\equiv 1(mod~ x^{\lceil \frac{n}{2} \rceil})\)

  • 事实上,我们能得到:\[A(x)\equiv R(x)(mod~x^n)\longrightarrow A(x)\equiv R(x)(mod ~x^{\lceil \frac{n}{2} \rceil})\]

推式

\[\begin{aligned}\F(x)G(x)&\equiv 1(mod~x^n)\F(x)H(x)&\equiv 1(mod~ x^{\lceil \frac{n}{2} \rceil})\F(x)G(x)&\equiv 1(mod~ x^{\lceil \frac{n}{2} \rceil})\F(x)(H(x)-G(x))&\equiv 0(mod~ x^{\lceil \frac{n}{2} \rceil})\H(x)-G(x)&\equiv 0(mod~ x^{\lceil \frac{n}{2} \rceil})\(H(x)-G(x))^2&\equiv 0(mod~x^n)\H(x)^2-2H(x)G(x)+G(x)^2&\equiv 0(mod~x^n)\F(x)(H(x)^2-2H(x)G(x)+G(x)^2)&\equiv 0 (mod~x^n)\(F(x)H(x))H(x)-(F(x)H(x))(2G(x))+F(x)G(x)^2&\equiv 0(mod~x^n)\H(x)-2G(x)+F(x)G(x)^2&\equiv 0(mod~x^n)\H(x)&\equiv 2G(x)-F(x)G(x)^2(mod~x^n)\\end{aligned}\]

具体实现

我们可以至底\(x^1\)向上求出\(G(x)\)

由于次数在模意义的下次数较大时会消掉,所以我们并不需要每次都\(NTT(x)\)

忽略常数及栈空间,递归求解感觉更舒服

手玩

我们是在系数模\(Mod\)的基础上进行的,所以最好\(F(x)G(x)\)的形态为,常数项为\(1\)\(~_{i=1}^{n-1}k_i \equiv 0(mod ~Mod)\),而其他项均能消掉

code

#include<bits/stdc++.h>
typedef long long LL;
const LL mod=998244353,maxn=1e6+9,g=3;
inline LL Read(){
    LL x(0),f(1); char c=getchar();
    while(c<'0' || c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0' && c<='9'){
        x=(x<<3)+(x<<1)+c-'0'; c=getchar();
    }
    return x*f;
}
inline LL Pow(LL base,LL b){
    LL ret(1ll);
    while(b){
        if(b&1) ret=ret*base%mod;
        base=base*base%mod; b>>=1;
    }
    return ret;
}
LL r[maxn];
inline LL NTT(LL *a,LL n,LL type){
    for(LL i=0;i<n;++i) if(i<r[i]) std::swap(a[i],a[r[i]]);
    for(LL mid=1;mid<n;mid<<=1){
        LL wn(Pow(g,(mod-1)/(mid<<1)));
        if(type==-1) wn=Pow(wn,mod-2);
        for(LL R=mid<<1,j=0;j<n;j+=R){
            LL w(1);
            for(LL k=0;k<mid;++k,w=w*wn%mod){
                LL x(a[j+k]),y(w*a[j+mid+k]%mod);
                a[j+k]=(x+y)%mod; a[j+mid+k]=(x-y+mod)%mod;
            }
        }
    }
}
LL a[maxn],F[maxn],b[maxn];
void Solve(LL n,LL *G){
    if(n==1){
        G[0]=Pow(a[0],mod-2); return;
    }
    Solve(n+1>>1,G);
    LL limit(1),len(0);
    while(limit<(n<<1)){
        limit<<=1; ++len;
    }
    for(LL i=1;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<len-1);
    for(LL i=0;i<n;++i) F[i]=a[i];
    for(LL i=n;i<limit;++i) F[i]=0;
    NTT(G,limit,1); NTT(F,limit,1);
    for(LL i=0;i<limit;++i)
        G[i]=(2ll-F[i]*G[i]%mod+mod)%mod*G[i]%mod;
    NTT(G,limit,-1);
    for(LL i=0;i<limit;++i)
        G[i]=G[i]*Pow(limit,mod-2)%mod;
    for(LL i=n;i<limit;++i) G[i]=0;
}
int main(){
    LL n(Read());
    for(LL i=0;i<n;++i) a[i]=Read();
    Solve(n,b);
    for(LL i=0;i<n;++i) printf("%lld ",b[i]);
    return 0;
}

【模板】多项式求逆

标签:span   多项式   display   ons   std   const   mit   2-2   typedef   

原文地址:https://www.cnblogs.com/y2823774827y/p/10682143.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!