求逆元

博客介绍了两种求逆元的方法。方法一是扩展欧几里得,时间复杂度为O(logn),适用于个数不多但mod很大的情况;方法二是费马小定理/欧拉定理,时间复杂度为O(logmod),一般在mod为素数时使用,比扩欧快且好写。

方法一:扩展欧几里得

a∗b≡1(modp) ;
a∗b+k∗p=1 ;

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;
}

性能分析:

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

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

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

欧拉定理:若a、p互素,则有a^φ(p)≡1(modp) (费马小定理的一般形式)
a^φ(p)-1∗a≡1(modp)
a^φ(p)−1 就是a在mod p意义下的逆元。

LL qkpow(LL a,LL p,LL mod)
{
    LL ans=1,k=a%mod;
    while(p)
    {
        if(p&1)ans=ans*k%mod;
        k=k*k%mod;
        p>>=1;
    }
    return t;
}

LL getInv(LL a,LL mod)
{
    return qkpow(a,mod-2,mod);
}

性能分析:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值