逆元的定义用处以及简单求法

一,逆元的定义

当 ax≡1(modb), x即为 a 在mod b 意义下的逆元。
逆元的数学符号是 inv ,a 在mod b 意义下的逆元记作 inv(a,b)。注意不要写反了。
简单来说逆元就是在mod某个数意义下的倒数例如5x≡1(mod3)x=2是满足10=1(mod3)所以称2是5在mod3意义下的逆元、

二,逆元的应用

那么逆元有什么用呢?
(a + b) % p = (a%p + b%p) %p (对)
(a - b) % p = (a%p - b%p) %p (对)
(a * b) % p = (a%p * b%p) %p (对)
(a / b) % p = (a%p / b%p) %p (错)
在求余的过程中我们发现只有除法是不能分开运算的,而当a过大时,在计算除法过程中可能会造成比较大的精度损失,所以对于这种情况我们一般会把式子转换成那么(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p来进行计算。这样就解决了除法不能分开计算的问题。
需要注意只有a和p互质,a才有关于p的逆元

三.逆元的两种简单求法

1,费马小定理
费马小定理(Fermat’s little theorem)是数论中的一个重要定理,在1636年提出。如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)。 [1]
费马小定理规定了p一定为一个质数,所以a和p一定互质
那么双方在modp的意义下同时除a可得
a^(p-2) ≡1/a (mod p)
也就是a^(p-2) ≡ inv(a) (mod p)
所以inv(a) = a^(p-2) (mod p)
代码需要用快速幂实现,复杂度大概为o(logn)

 
LL pow(LL a, LL b, LL p){//a的b次方求余p 
    LL x = 1;
    while(b){
        if(b & 1) x = (x * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}
LL Fm(LL a, LL p){//费马求a关于b的逆元 
        return pow(a, p-2, p);
}

2.扩展欧几里得算法求逆元
如果gcd(a,p)=1;
那么就有ax+py=1
双方同时modp
就有ax≡1(modp)
因为py是p的倍数全部约掉了
此时x就是a的逆元
所以只需解出该情况下的扩展欧几里得方程的解问题就解决了

#include<cstdio>
typedef long long LL;
void exgcd(LL a,LL b,LL &x,LL &y,LL &d){
    if(b==0)  d=a,x=1,y=0;
    else  exgcd(b,a%b,x,y,d),t=x,x=y,y=t-a/b*y;
}
LL inv(LL t, LL p){//如果不存在,返回-1 
    LL d, x, y;
    ex_gcd(t, p, x, y, d);
    return d == 1 ? (x % p + p) % p : -1;
}
int main(){
    LL a, p;
    while(~scanf("%lld%lld", &a, &p)){
        printf("%lld\n", inv(a, p));
    }
}
  • 25
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值