乘法逆元的四种求法(拓展欧几里得、费马小定理、递归、递推)

前言

逆元:如果 a x 1 ( m o d <mtext>   </mtext> p ) a*x\equiv1(mod\ p) ax1(mod p),且a与p互质,则称x是a关于p的逆元。
对于这个概念和倒数有本质的区别,因为除法不能将mod数化进去。引用一个例子:

(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  (错)

为什么除法错的?
证明是对的难,证明错的只要举一个反例
(100/50)%20 = 2 ≠ (100%20) / (50%20) %20 = 0

对于一些题目,我们必须在中间过程中进行求余,否则数字太大,电脑存不下,那如果这个算式中出现除法,我们是不是对这个算式就无法计算了呢?

答案当然是 NO (>o<)
这时就需要逆元了

我们知道:
如果
ax = 1
那么x是a的倒数,x = 1/a
但是a如果不是1,那么x就是小数
那数论中,大部分情况都有求余,所以现在问题变了
a
x = 1 (mod p)
那么x一定等于1/a吗?

不一定
所以这时候,我们就把x看成a的倒数,只不过加了一个求余条件,所以x叫做 a关于p的逆元
比如2 * 3 % 5 = 1,那么3就是2关于5的逆元,或者说2和3关于5互为逆元
这里3的效果是不是跟1/2的效果一样,所以才叫数论倒数

a的逆元,我们用inv(a)来表示

那么(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p
这样就把除法,完全转换为乘法了。

以上的例子摘自这篇博客,强推,浅显易懂!


对于法三用到如下公式变形:

证明:
设x = p % a,y = p / a
于是有 x + y * a = p
(x + y * a) % p = 0
移项得 x % p = (-y) * a % p
x * inv(a) % p = (-y) % p
inv(a) = (p - y) * inv(x) % p
于是 inv(a) = (p - p / a) * inv(p % a) % p

法四就是法三的记忆化版或者说是递推版

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

//拓展欧几里得
LL exgcd(LL A, LL B, LL &x, LL &y) {
  if (B == 0) {
    x = 1;
    y = 0;
    return A;
  }
  LL gcdnum = exgcd(B, A % B, x, y);
  LL tmp = y;
  y = x - A/B*y; //算上来的x,y计算出新的x,y
  x = tmp;
  return gcdnum;
}

//中速乘 : 对于长整型的快速乘要利用到80为的long double的特性O(1) 本算法复杂度O(logN)
LL qmul(LL a, LL b, LL mod) {
  LL ans = 0;
  a %= mod;
  while (b) {
    if (b&1) {
      ans = (ans + a) % mod;
    }
    a = (a << 1) % mod;
    b >>= 1;
  }
  return ans;
}

//快速幂
LL qpow(LL a, LL b, LL mod) {
  LL ans = 1;
  a %= mod;
  while (b) {
    if (b & 1) {
      ans = qmul(ans, a, mod);
    }
    a = qmul(a, a, mod);
    b >>= 1;
  }
  return ans;
}

//逆元的三种求法求法:

//法一:根据费马小定理转换 O(logP)
LL inv_1(LL a, LL p) {  //a关于p的逆元(数论倒数)
  return qpow(a, p-2, p);
}

//法二:根据拓展欧几里得求逆元
LL inv_2(LL a, LL p) {
  LL x, y;
  if (exgcd(a, p, x, y) != 1) return -1; //不满足a p 互质
  return (x % p + p) % p; //变为正的
}

//法三:递归版 (原理就是一个式子化简 至于怎么构造还不会,待补 参考:https://www.cnblogs.com/linyujun/p/5194184.html)
LL inv_3(LL a, LL p) {
  //求a关于p的逆元,注意:a要小于p,最好传参前先把a%p一下
  return a == 1 ? 1 : (p - p / a) * inv_3(p % a, p) % p;
}

const int maxn = (int)2e5 + 5;
const int MOD = (int)1e9 + 7;
int inv[maxn];
void inv_4(){ //法三递推版 O(n)
  inv[1] = 1;
  for(int i = 2; i < maxn; i ++){
      inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
  }
}

int main() {
  cout << "inv_1 : " << inv_1(100, MOD) << endl;
  cout << "inv_2 : " << inv_2(100, MOD) << endl;
  cout << "inv_3 : " << inv_3(100, MOD) << endl;
  inv_4();
  cout << "inv_4 : " << inv[100] << endl;
  return 0;
}


关于费马小定理:假如p是质数,且gcd(a,p)=1(a和p互质),那么 a^(p-1) ≡ 1(mod p),即 ( a^(p-1) )%p = 1。

  • 可以用这个定理快速求得一个大数的余数。例如:
    2 100 <mtext>   </mtext> % <mtext>   </mtext> 13 = <mtext>   </mtext> ? 欲求:2^{100}\ \%\ 13=\ ? 2100 % 13= ?
    2 13 2 13 1 1 ( m o d <mtext>   </mtext> 13 ) 因为2与13互质,故根据费马小定理有:2^{13-1}\equiv1(mod\ 13) 21321311(mod 13)
    2 12 <mtext>   </mtext> % <mtext>   </mtext> 13 = 1 即:2^{12}\ \%\ 13 = 1 212 % 13=1
    2 100 = ( 2 12 ) 8 2 4 又:2^{100}=(2^{12})^{8}*2^4 2100=(212)824
    2 100 <mtext>   </mtext> % <mtext>   </mtext> 13 = ( 2 12 ) 8 2 4 <mtext>   </mtext> % <mtext>   </mtext> 13 = ( ( 2 12 ) 8 <mtext>   </mtext> % <mtext>   </mtext> 13 ) ( 2 4 <mtext>   </mtext> % <mtext>   </mtext> 13 ) <mtext>   </mtext> % <mtext>   </mtext> 13 = ( ( 2 12 <mtext>   </mtext> % <mtext>   </mtext> 13 ) 8 <mtext>   </mtext> % <mtext>   </mtext> 13 ) ( 3 ) <mtext>   </mtext> % <mtext>   </mtext> 13 = 3 所以,2^{100}\ \%\ 13=(2^{12})^{8}*2^4\ \%\ 13=((2^{12})^{8}\ \%\ 13)*(2^4\ \%\ 13)\ \%\ 13=((2^{12}\ \%\ 13)^8\ \%\ 13)*(3)\ \%\ 13=3 2100 % 13=(212)824 % 13=((212)8 % 13)(24 % 13) % 13=((212 % 13)8 % 13)(3) % 13=3
全部评论

相关推荐

09-27 00:29
东北大学 Java
伟大的麻辣烫:查看图片
阿里巴巴稳定性 75人发布 投递阿里巴巴等公司10个岗位
点赞 评论 收藏
分享
ProMonkey2024:5个oc?厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了(别的帖子偷来的,现学现卖😋)
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务