2021-08-17三期集训第九天----四种求逆元的方法

                   

简述逆元

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

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

注意

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

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

a∗b≡1(mod p) a∗b+k∗p=1 然后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;
}

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

原理

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

欧拉定理:若a、p互素,则有a^φ(p)≡1(mod p)(费马小定理的一般形式) a^φ(p)∗a≡1(mod p) a^(φ(p)−1)就是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);
}

方法三:递推求逆元

原理

可以这样考虑,设

t = ⌊ p/ i ⌋ t

k = p % i

则有

p = i × t + k

也就是

i × t + k ≡ 0 ( m o d p )

移项

i × t ≡ − k ( m o d p )

设i ′ 为i 对于模p的逆元,k ′ 为k 对于模p的逆元,两侧分别乘上i ′ k ′ ,得

i × t × i ′ × k ′ ≡ − k × i ′ × k ′ ( m o d p )

由于i × i ′ ( m o d p ) 为1,k × k ′ ( m o d p ) 为1,所以

t × k ′ ≡ − i ′ ( m o d p )

如果用数组inv表示逆元(inverse element),那么上式等价于 t × i n v [ k ] ≡ − i n v [ i ] ( m o d p )

将k和t代入,可得 ⌊ p i ⌋ × i n v [ p % i ] ≡ − i n v [ i ] ( m o d p )

也就是i n v [ i ] = − ⌊ p i ⌋ × i n v [ p % i ] % p

负数化正,得到i n v [ i ] = ( p − ⌊ p i ⌋ × i n v [ p % i ] % p ) % p

代码

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

方法四:递归求逆元

代码

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值