求逆元的三种方法

  • 逆元是什么?
  • 方法一: 最简便的方法
  • 方法二: 费马小定理
  • 方法三: 扩展欧几里得

逆元是什么?

每个数a均有唯一的一个与之对应的乘法逆元x,使得(a * x)%m = 1
一个数有逆元的充分必要条件是gcd(a,m)=1,此时逆元唯一存在

逆元的含义:模m意义下,1个数a如果有逆元x,那么对于一个数k有k/a=k*x

方法一: 最简便的方法

最简便的一种方法是

这里写图片描述

方法二: 费马小定理

还是上面的例子, 因为除数可能会很大,超过int范围,所以如果当除数特别大的时候就需要求逆元

如果我告诉你我知道 1bmodm 1 b m o d m 的结果会怎么样,那么你就可以用 amodm1bmodm a m o d m 1 b m o d m 就可以得到结果了是不是?

这里 1bmodm 1 b m o d m 就是b相对于m的乘法逆元.

当然我们的费马大大和一众数学家不是这么理解的。费马小定理a ^ (p-1) = 1 (%p),两边同时除去a——a ^ (p-2) = a^-1 (%p),得a的逆元a^-1 = a ^ (p-2)。(参考自链接)。所以我们的(1/b)modm就是b^(mod-2)咯,用快速幂可以快速地完成这个工作。

下面用快速幂的方法来求逆元,但是这里的mod一定要是一个质数

ll inv(ll a,ll p)
{
    ll m=p-2,ans=1;
    while(m)
    {
        if(m&1) ans=ans*n%p;
        m>>=1;
        a=a*a%p;
    }
    return ans;
}

方法三: 扩展欧几里得

但是注意的是当mod是与不是质数的时候求的方法是不一样的,下面用扩展欧几里得求逆元是可以忽略mod是否质数的问题的

给定模数m,求a的逆相当于求解(a * x)%m = 1
这个方程可以转化为ax-my=1
然后套用求二元一次方程的方法,用扩展欧几里得算法求得一组x0,y0和gcd
检查gcd是否为1
gcd不为1则说明逆元不存在
若为1,则调整x0到0~m-1的范围中即可

//a对b求逆元
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    ll t,gcd;
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    gcd=exgcd(b,a%b,x,y);
    t=x,x=y,y=t-a/b*y;
    return gcd;
}
ll inv(ll a,ll b)
{
    ll x,y;
    exgcd(a,b,x,y);
    x%=b;
    x=(x+b)%b;
    return x;
}

int main(){
    ll x,y;//x和y不需要进行初始化
    exgcd(a,b,x,y);
    //(x+m)%m即是a相对于b的乘法逆元
}

你可能感兴趣的:(▶︎算法与数据结构)