逆元的求法总结(3种基本方法+4种实现)

原创

逆元的求法总结(3种基本方法+4种实现)

逆元(Inverse element)就是在mod意义下,不能直接除以一个数,而要乘以它的逆元。
比如ab1(modp)a∗b≡1(modp),那么a,b互为模n意义下的逆元,比如你要算x/a,就可以改成x*b%p

观察ab1(modp)a∗b≡1(modp),就可以用扩展欧几里得算法求a了,同时这里也说明了a和p只有在互素的情况下才存在逆元。

注意

在下面所有的算法中,最好先把除数取个模再运算。

方法一:扩展欧几里得算法

原理

ab1(modp)a∗b≡1(modp)
然后a就是我们要求的逆元,最终得到一个正数a的话就要对a mod p,因为a加上mp的时侯k减少mb可以使得等式依然成立。

如果你不想让逆元为正数,那么直接返回x也是可以正确的逆元

代码

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 mod)//求a在mod下的逆元,不存在逆元返回-1 
{
    LL x,y;
    LL d=exgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意:返回的时候可以改成(x+mod)%mod,因为扩展欧几里得算法算出来的x应该不会太大.

性能分析:

  • 时间复杂度:O(logn)(实际是斐波那契数列)
  • 适用范围:只要存在逆元即可求,适用于个数不多但是mod很大的时候,也是最常见的一种求逆元的方法。

方法二:费马小定理/欧拉定理

原理

费马小定理:若p为素数,则有ap11(modp)ap−1≡1(modp)就是a在mod p意义下的逆元啦。

欧拉定理:若a、p互素,则有aφ(p)1(modp)aφ(p)≡1(modp)就是a在mod 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 mod)
{
    return qkpow(a,mod-2,mod);
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

性能分析:

  • O(logmod)
  • 适用范围:一般在mod是个素数的时候用,比扩欧快一点而且好写。
  • 但是如果是合数,相信一般没人无聊到去算个欧拉函数。

方法三:递推求逆元

原理

p是模数,i是待求的逆元,我们求的是i1i−1
嗯。。好难看的公式
说白了就是:inv[i]=-(mod/i)*inv[i%mod]
然后边界是inv[1]=1
这不仅为我们提供了一个线性求逆元的方法,也提供了一种O(logmod)求逆元的方法

代码

线性求逆元
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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意:

  • 调用前要先预处理
  • 调用的时候要先对除数取mod

性能分析:

  • 时间复杂度O(n)
  • 适用范围:mod数是不大的素数而且多次调用,比如卢卡斯定理。
递归求逆元
LL inv(LL i)
{
    if(i==1)return 1;
    return (mod-mod/i)*inv(mod%i)%mod;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

性能分析

  • 时间复杂度:O(logmod)
  • 好像找到了最简单的算法了!!
  • 适用范围: mod数是素数,所以并不好用,比如中国剩余定理中就不好使,因为很多时候可能会忘记考虑mod数是不是素数。
文章最后发布于: 2018-03-23 15:49:12
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值