数论(2) | 逆元

1 什么是逆元

如果ax≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p的乘法逆元为x。

2 逆元求法①拓展欧几里得(洛谷P1082)

【算法原理】

观察ax≡1 (mod p),变形为a*x+p*y=1,就可以用扩展欧几里得算法求x了,同时这里也说明了a和p只有在互素的情况下才存在逆元。

【适用范围】

只要存在逆元即可求,适用于个数不多但是mod很大的时候,也是最常见的一种求逆元的方法。

【程序代码】

LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法 
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    LL ret=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}
LL getInv(int a,int p)//求a在p下的逆元,不存在逆元返回-1 
{
    LL x,y;
    LL d=exgcd(a,p,x,y);
    return d==1?(x%p+p)%p:-1;
}

3 逆元求法②费马小定理

【算法原理】

若p为素数,则有ap-≡ 1(mod p)

变换一下:
ap-2*a ≡ 1(mod p)
ap-2就是a在mod p意义下的逆元啦。

【适用范围】

一般在p是个素数的时候用,比拓展欧几里得快一点而且好写。(但仅限素数)

LL qkpow(LL a,LL p,LL mod)
{
    LL t=1,tt=a%mod;
    while(p)
    {
        if(p&1)t=t*tt%mod;
        tt=tt*tt%mod;
        p>>=1;
    }
    return t;
}
LL getInv(LL a,LL p)
{
    return qkpow(a,p-2,p);
}

4 逆元求法③递推求逆元(洛谷P3811)

【算法原理】

(这里准备好草稿纸嗷)

p是模数,i是待求的逆元,我们现在要求i在mod p意义下的逆元 i-1

即:i*x+r ≡ 1 (mod p)

首先,当i=1时,i-1=1

当2≤i<p时,i*i-1 ≡ 1 (mod p)

令,则p = k*i+r

k∗i+r ≡ 0 (modp)

式子两边同乘r−1,i−1,因为r*r−1 ≡ 1 (mod p)  , i*i−1 ≡ 1 (mod p)

因此k∗r−1+i−1 ≡ 0 (mod p)

i−1 ≡ −k*r−1 (mod p)

i−1 ≡ −p/i*inv[p mod i]

公式有点丑,说白了就是:

inv[1]=1

inv[i] = -(p/i)*inv[i%p]

【适用范围】求一连串的数字的逆元时非常使用,但要保证i<p

【顺序实现】

LL inv[mod+5];
void getInv(LL mod)
{
    inv[1]=1;
    for(int i=2;i<mod;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}

【递归实现】

在此基础上我们用递归写程序,可以用来求不连续的数字的逆元

LL inv(LL i)
{
    if(i==1)return 1;
    return (p-p/i)*inv(p%i)%p;
}

这个就是求逆元最简单的算法了!!

 

上一篇:吴恩达机器学习 | 复习线性代数


下一篇:数论(2)逆元