乘法逆元 (扩展欧几里得或费马小定理)

本文介绍欧拉定理及其应用,包括逆元的概念及如何利用扩展欧几里得算法、费马小定理等方法求解逆元。通过具体的数学推导和编程实现,帮助读者深入理解并掌握逆元的计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

欧拉定理(又称费马-欧拉定理):已知a和n为正整数,并且a和p互素,则a^phi(n) ≡ 1(mod n)。

证明:

  设集合Z = {X1, X2, X3, .... , Xphi(n)},其中Xi (i = 1, 2, .. phi(n))表示第i个不大于n与n互质的数。

  考虑集合S = {a*X1(mod n), a*X2(mod n), ... ,a*Xphi(n) (mod n) },则集合Z = S;

  1) 因为a和n互质,Xi和n也互质,所以a*Xi 也与n互质。所以对任意一个Xi,a*Xi (mod n)一定是Z里面的元素;

  2)对于任意Xi, Xj, 如果Xi != Xj,则a*Xi(mod n) != a*Xj(mod n);

  所以S = Z;

  那么 (a*X1*a*X2*...*a*Xphi(n))(mod n) ---------------------------------------------------- (1)

  = (a*X1(mod n)* a*X2(mod n)* ... *a*Xphi(n) (mod n)) (mod n)

  = (X1* X2* X3* .... * Xphi(n)) (mod n) ------------------------------------------------------ (2)

  式(1)整理得 [a^phi(x) * (X1* X2* X3* .... * Xphi(n))] (mod n)

  与(2)式一同消去 (X1* X2* X3* .... * Xphi(n)),即得 a^phi(n) ≡ 1 (mod n);

逆元 :(b/a) (mod n) = (b * x) (mod n)。 x表示a的逆元。并且 a*x ≡ 1 (mod n )  注意:只有当a与n互质的时候才存在逆元

因为a^phi(n) ≡ 1 (mod n),所以x可以表示为a^(phi(n) - 1)。如果n为质数,phi(n)=n-1


/*扩展欧几里得的应用:
模P乘法逆元
对于整数a、p,如果存在整数b,满足ab mod p =1,则说,b是a的模p乘法逆元。
定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1


注意,逆元也可以这样理解,求一个最小的正整数x(逆元),使a乘以x对m的取余等于1对m的取余, 所以m=1 时,逆元为1

证明:
首先证明充分性
如果gcd(a,p) = 1,根据欧拉定理,aφ(p) ≡ 1 mod p,因此
显然aφ(p)-1 mod p是a的模p乘法逆元。

再证明必要性
假设存在a模p的乘法逆元为b
ab ≡ 1 mod p
则ab = kp +1 ,所以1 = ab - kp
因为gcd(a,p) = d
所以d | 1
所以d只能为1 
扩展欧几里德算法对于最大公约数的计算和普通欧几里德算法是一致的。计算乘法逆元则显得很难明白。下面是证明:

首先重复拙作整除中的一个论断:

如果gcd(a,b)=d,则存在m,n,使得d = ma + nb,称呼这种关系为a、b组合整数d,m,n称为组合系数。当d=1时,有 ma + nb = 1 ,此时可以看出m是a模b的乘法逆元,n是b模a的乘法逆元。
(按照上面算出来的m,n可能为负数,最后要把它转化为正数)。完整程序如下:*/


一般情况下,ax+by=1;得 x为a mod  b 的逆元,y为 b mod a的逆元


[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. int extended_gcd(int a,int b, int &x, int &y)  
  4. {  
  5. if (b == 0)  
  6. {  
  7. x = 1;  
  8. y = 0;  
  9. return a;  
  10. }  
  11. else  
  12. {  
  13. int gcd = extended_gcd(b, a % b, x, y);  
  14. int t=x%mod;  
  15.    x=y%mod;  
  16.    y=((t-a/b*x)%mod+mod)%mod;  
  17. return gcd;  
  18. }  
  19. }  
  20. int main()  
  21. {  
  22. int i, x, y;  
  23. const int P = 13;  
  24. for (i = 1; i < P; ++i)  
  25. {  
  26. extended_gcd(i, P, x, y);  
  27. while (x < 0) x += P;  
  28. printf("1 div %d = %d\n", i, x);  
  29. }  
  30. return 0;  
  31. }  

费马小定理求逆元


[cpp]  view plain copy
  1. //费马小道理求逆元  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<math.h>  
  5. #include<string.h>  
  6. using namespace std;  
  7.   
  8. #define N 1005  
  9. int b[N],prime[N],phi[N];  
  10. void inint()  //求欧拉函数 和 素数  
  11. {  
  12.     int i,j,k,c=0;  
  13.     memset(b,0,sizeof(b));  
  14.     for(i=2;i<N;i++)  
  15.     {  
  16.         if(b[i]==0)  
  17.         {  
  18.             prime[++c]=i;  
  19.             phi[i]=i-1;  
  20.         }  
  21.         for(j=1;(j<=c)&&(k=i*prime[j])<N;j++)  
  22.         {  
  23.             b[k]=1;  
  24.             if(i%prime[j])  
  25.             {  
  26.                phi[prime[j]*i]=phi[i]*(prime[j]-1);  
  27.   
  28.             }  
  29.             else phi[prime[j]*i]=phi[i]*prime[j];  
  30.         }  
  31.     }  
  32. }  
  33.   
  34. int m;  
  35. int poww(int a,int n)  
  36. {  
  37.    int r=1,p=a;  
  38.    while(n>0)  
  39.    {  
  40.        if(n&1) r=(r*p)%m;  
  41.        p=(p*p)%m;  
  42.        n>>=1;  
  43.    }  
  44.    return r;  
  45. }  
  46.   
  47. int main()  
  48. {  
  49.     int t,a,i,j,f;  
  50.     inint();  
  51.     scanf("%d",&t);  
  52.     while(t--)  
  53.     {  
  54.         scanf("%d%d",&a,&m);  
  55.         f=0;  
  56.         if(m==1)  //注意 m为1时,逆元都为1  
  57.         {  
  58.              puts("1");  
  59.             continue;  
  60.         }  
  61.         for(i=1;;i++)  
  62.         {  
  63.             if(prime[i]>a||prime[i]>m) break;  
  64.             if(a%prime[i]==0&&m%prime[i]==0)  
  65.             {  
  66.                 f=1;  
  67.                 break;  
  68.             }  
  69.         }  
  70.         if(f)  //a和m 不互素,不存在逆元  
  71.   
  72.         {  
  73.             puts("Not Exist");  
  74.             continue;  
  75.         }  
  76.         int x=poww(a,phi[m]-1);  //求解 a 模 m 的逆元  
  77.         x=(x%m+m)%m;  
  78.         printf("%d\n",x);  
  79.     }  
  80.     return 0;  
  81. }  


//扩展的欧几里德算法求乘法逆元


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. int ExtendedEuclid(int f, int d, int *result);  
  3. int main() {  
  4. int x, y, z;  
  5. z = 0;  
  6. printf("输入两个数:\n");  
  7. scanf("%d%d", &x, &y);  
  8. if (ExtendedEuclid(x, y, &z))  
  9. printf("%d和%d互素,乘法的逆元是:%d\n", x, y, z);  
  10. else  
  11. printf("%d和%d不互素,最大公约数为:%d\n", x, y, z);  
  12. return 0;  
  13. }  
  14.   
  15. int ExtendedEuclid(int f, int d, int *result)//求f 模  d 的 逆元<pre name="code" class="cpp"> {  
  16. int x1, x2, x3, y1, y2, y3, t1, t2, t3, q;  
  17. x1 = y2 = 1;  
  18. x2 = y1 = 0;  
  19. x3 = d;  
  20. y3 = f;  
  21. while (1) {  
  22. if (y3 == 0) {  
  23. *result = x3; /* 两个数不互素则result为两个数的最大公约数,此时返回值为零 */  
  24. return 0;  
  25. }  
  26. if (y3 == 1) {  
  27. *result = y2; /* 两个数互素则resutl为其乘法逆元,此时返回值为1 */  
  28. return 1;  
  29. }  
  30. q = x3 / y3;  
  31. t1 = x1 - q*y1;  
  32. t2 = x2 - q*y2;  
  33. t3 = x3 - q*y3;  
  34. x1 = y1;  
  35. x2 = y2;  
  36. x3 = y3;  
  37. y1 = t1;  
  38. y2 = t2;  
  39. y3 = t3;  
  40. }  
  41.   
  42. }</pre><br>  
  43. <pre></pre>  
  44. <pre></pre>  
<think>我们已知费马小定理:如果 \( p \) 是一个质数,而整数 \( a \) 不是 \( p \) 的倍数,那么有 \( a^{p-1} \equiv 1 \pmod{p} \)。 由费马小定理可得:\( a \cdot a^{p-2} \equiv 1 \pmod{p} \)。 因此,在模 \( p \) 的意义下,\( a \)乘法逆元就是 \( a^{p-2} \)(这里要求 \( p \) 是质数且 \( a \) 不是 \( p \) 的倍数)。 计算乘法逆元的步骤: 1. 确认模数 \( p \) 是质数,且 \( a \) 不是 \( p \) 的倍数(即 \( a \mod p \neq 0 \))。 2. 使用快速幂算法计算 \( a^{p-2} \mod p \),结果即为 \( a \) 模 \( p \)乘法逆元。 注意:如果 \( a \) 是 \( p \) 的倍数,则乘法逆元不存在。 快速幂算法(参考引用[4]): 快速幂通过将指数进行二进制分解来高效计算幂模。具体步骤如下: - 初始化结果变量为1。 - 当指数不为0时: - 如果指数是奇数,将结果乘以底数并取模。 - 底数平方并取模。 - 指数右移一位(即除以2)。 示例代码(引用[4]中的代码): ```cpp #include<bits/stdc++.h> using namespace std; #define int long long int qp(int a, int b, int p) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = (res * a) % p; a = (a * a) % p; } return res; } signed main() { int tt; cin >> tt; while (tt--) { int a, p; cin >> a >> p; if (a % p == 0) { cout << "impossible" << endl; } else { // 计算逆元:a^(p-2) mod p int res = qp(a, p-2, p); cout << res << endl; } } return 0; } ``` 解释: - 函数 `qp` 是快速幂函数,计算 \( a^b \mod p \)。 - 在主函数中,首先判断 `a % p` 是否为0,如果为0则输出"impossible",否则计算 \( a^{p-2} \mod p \) 并输出。 注意事项: - 费马小定理只适用于模数为质数的情况。如果模数不是质数,则需要使用扩展欧几里得算法(如引用[2]和[5]所述)。 - 当模数 \( p \) 很大时,快速幂算法效率很高(时间复杂度为 \( O(\log p) \))。 总结:使用费马小定理乘法逆元的前提是模数 \( p \) 为质数且 \( a \) 与 \( p \) 互质(即 \( a \) 不是 \( p \) 的倍数)。计算方法为 \( a^{p-2} \mod p \)。 §§相关问题§§ 1. 如果模数不是质数,如何求乘法逆元? 2. 快速幂算法的时间复杂度是多少?它是如何工作的? 3. 费马小定理的证明过程是怎样的? 4. 乘法逆元在密码学中有哪些应用?</think>### 使用费马小定理计算乘法逆元 费马小定理是求解模运算中乘法逆元的重要方法,特别适用于**模数为质数**的场景。其核心原理和计算步骤如下: #### 1. **费马小定理** 若 \( p \) 是质数,且整数 \( a \) 满足 \( \gcd(a, p) = 1 \)(即 \( a \) 不是 \( p \) 的倍数),则: $$ a^{p-1} \equiv 1 \pmod{p} $$ 变形后可得: $$ a \cdot a^{p-2} \equiv 1 \pmod{p} $$ 因此,**\( a \) 模 \( p \)乘法逆元**为: $$ a^{-1} \equiv a^{p-2} \pmod{p} $$ #### 2. **计算步骤** 1. **验证条件**: - \( p \) 必须是质数。 - \( a \not\equiv 0 \pmod{p} \)(否则逆元不存在)。 2. **计算 \( a^{p-2} \mod p \)**: - 使用**快速幂算法**高效计算(时间复杂度 \( O(\log p) \))。 #### 3. **快速幂算法实现** ```python def mod_inverse(a, p): # 验证条件 if a % p == 0: # a是p的倍数,逆元不存在 return None # 计算 a^{p-2} mod p result = 1 exponent = p - 2 base = a % p while exponent: if exponent & 1: # 指数为奇数 result = (result * base) % p base = (base * base) % p # 底数平方 exponent >>= 1 # 指数右移(整除2) return result ``` #### 4. **示例** - 求 \( a=3 \) 在模 \( p=11 \)(质数)下的逆元: $$ 3^{-1} \equiv 3^{11-2} = 3^9 \pmod{11} $$ 计算过程: $$ 3^1 \equiv 3, \quad 3^2 \equiv 9, \quad 3^4 \equiv 81 \equiv 4, \quad 3^8 \equiv 4^2 \equiv 16 \equiv 5, \quad 3^9 \equiv 5 \times 3 \equiv 15 \equiv 4 \pmod{11} $$ 验证: \( 3 \times 4 = 12 \equiv 1 \pmod{11} \),正确。 #### 5. **注意事项** - **适用条件**:仅当 \( p \) 为质数且 \( a \not\equiv 0 \pmod{p} \) 时有效。 - **效率**:快速幂算法在 \( O(\log p) \) 时间内完成计算,适合大数运算。 - **扩展**:若 \( p \) 非质数,需改用**扩展欧几里得算法**[^2][^5]。 #### 6. **代码验证(引用[4])** ```cpp #include<bits/stdc++.h> using namespace std; int qp(int a, int b, int p) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = (res * 1LL * a) % p; // 防止溢出 a = (a * 1LL * a) % p; } return res; } int main() { int a = 3, p = 11; if (a % p == 0) cout << "impossible"; else cout << qp(a, p-2, p); // 输出 4 return 0; } ``` > **关键点**:费马小定理逆元计算转化为模幂运算,快速幂通过二进制分解指数显著提升效率[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值