逆元

关于逆元的4种求法总结。

扩欧求解

运用扩展欧几里得求解逆元。

\(ax+by=1\) 其中 \(a\) 是将求的数,\(x\) 是逆元,\(b\) 是模数。

int exgcd(int a,int b,int &x,int &y)
{
    if(!b){x=1,y=0;return a;}
    int res=exgcd(b,a%b,x,y);
    int tmp=x;
    x=y;y=tmp-a/b*y;
    return res;
}
int exgcd_inv(int a,int mod)
{
    int d,x,y;
    d=exgcd(a,mod,x,y);
    return d==1?(x+mod)%mod:-1;
}

费马小定理求解

利用快速幂和费马小定理。

\(p\) 为质数时,有 \(a^{p-1}\equiv 1\ (mod\ p)\)

可得: \(a·a^{p-2}\equiv 1\ (mod\ p)\)\(a^{p-2}\) 就是 \(a\) 的逆元。

int ksm(int x,int y,int mod)
{
    int res=1;
    while(y)
    {
        if(y&1)res=res*x%mod;
        x=x*x%mod,y>>=1;
    }
    return res;
}
int fermat_inv(int x,int mod){return ksm(x,mod-2,mod);}

线性求逆元

证明:

首先,\(1^{-1}\equiv 1\ (mod\ p)\)

\(p=k*i+r,r<i\) ,可得 \(k\times i+r\equiv 0\ (mod\ p)\)

两边同乘 \(i^{-1},r^{-1}\)\(k\times r^{-1}+i^{-1}\equiv 0\ (mod\ p)\)

移项得 \(i^{-1}\equiv -k\times r^{-1}\) ,消元得 \(i^{-1}\equiv -\lfloor \frac{p}{i}\rfloor\times (p\ mod\ i)\ (mod\ p)\)

因为此时求的逆元为负数,我们需要将它变正,可以加上一个 \(p\times r^{-1}\)

最后得 \(i^{-1}\equiv (p-\lfloor \frac{p}{i}\rfloor)\times (p\ mod\ i)\ (mod\ p)\)

inv[1]=1;
for(int i=1;i<mod;++i)
    inv[i]=(mod-mod/i)*inv[mod%i]%mod;

递归求逆元

我们可以从线性求逆元发现, \(i\) 的逆元只与 \(p\ mod\ i\) 有关,所以我们可以递归求解逆元,时间复杂度和费马小定理求解都是 \(O(logn)\) 的时间复杂度。

为了防止爆 $long\ long $ ,我们可以用 __int128 进行乘法取模来保证正确性。

int gsc(int x,int y){return (__int128)x*y%p;}
int inv(int x){return x==1?1:gsc(p-p/x,inv(p%x));}

这种求逆元方法代码极短!很方便!

总结

扩展欧几里得求解是最快的,常数小,但比较难写。

费马小定理求解从各各方面来看都没有递归求解好,所以很不理解很多人推崇它的理由。

线性求逆元是 \(O(n)\) 时间复杂度,在大量用到逆元时适合用线性来预处理逆元。

posted @ 2022-03-24 11:40  violetctl39  阅读(100)  评论(0编辑  收藏  举报