求逆元的四種方法


 

如果ax1(mop),且a與p互質(gcd(a,p)=1),則稱a關於模p的乘法逆元為x。(不互質則乘法逆元不存在)

求逆元的四種方法:

  1. 費馬小定理
  2. 歐拉定理求逆元 (相當於費馬小定理的擴展)
  3. 擴展歐幾里德
  4. 遞推打表

1、費馬小定理 (p為素數)

 

費馬小定理:  ( a^p - p ) 是 p 的倍數,所以可推出 a^{{p-1}}\equiv 1{\pmod  {p}} , 這也是更為常用的書寫形式。

因為 a^(p-1) = a * a^(p-2) , 故費馬小定理可寫成逆元的形式,( a * a^(p-2) ) ≡ 1 (mod p)

因此 a^(p-2) 就是所求的逆元,用快速冪求出即可。

 

 1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 
 2     LL ret = 1;
 3     while(b){
 4         if(b & 1) ret = (ret * a) % p;
 5         a = (a * a) % p;
 6         b >>= 1;
 7     }
 8     return ret;
 9 }
10 LL Fermat(LL a, LL p){//費馬求a關於b的逆元 
11         return pow_mod(a, p-2, p);
12 }
View Code

 

2、歐拉定理求逆元

 

摘自大佬博客: https://www.cnblogs.com/vongang/archive/2013/06/04/3117370.html

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<stack>
 8 #include<deque>
 9 #include<iostream>
10 using namespace std;
11 typedef long long  LL;
12 const int N = 100009;
13 
14 int check[N];
15 int prime[N];
16 int phi[N];
17 int inv[N];
18 int cnt;
19 
20 int fast_pow(int a,int b)
21 {
22     int ans=1;
23     while(b)
24     {
25         if(b&1)
26             ans=a*ans;
27         a=a*a;
28         b>>=1;
29     }
30     return ans;
31 }
32 
33 void is_prime(int n)
34 {
35     int i,p,j;
36     cnt=0;
37     phi[1]=1;
38     for(i=2;i<=n;i++)
39     {
40         if(!check[i])
41         {
42             prime[cnt++]=i;
43             phi[i]=i-1;
44         }
45         for(j=0;j<cnt;j++)
46         {
47             if(i*prime[j]>n)
48                 break;
49             check[i*prime[j]]=1;
50 
51             if(i%prime[j]==0)
52             {
53                 phi[i*prime[j]]=phi[i]*prime[j];
54                 break;
55             }
56             else
57             {
58                 phi[i*prime[j]]=phi[i]*(prime[j]-1);
59             }
60         }
61     }
62 }
63 int main()
64 {
65     int i,p,j,n;
66     is_prime(100);
67     scanf("%d",&p);
68     for(i=0;i<=10;i++)
69         if(i%p)
70             inv[i]=(fast_pow(i,phi[p]-1)%p);    //// i關於1模p的逆元
71         else
72             inv[i]=-1;
73     for(i=0;i<=10;i++)
74     {
75         printf("%d ",inv[i]);
76     }
77     return 0;
78 }
View Code

 

3、擴展歐幾里德

  

  a*x=1 (mod p)  相當於 a*x-y*p=1 (y為整數,最小的x應當是y等於零的時候,所以最后的時候把y賦成0)

  a*x-y*p=1 , 為了便於理解,將p寫成b,

  即, a*x+b*y=1。 理解為 a關於 1 模 b 的乘法逆元為 x 。

  

  開始的 x,y,d 為任意值,但是不能等於零!!!

  因為d是 gcd(a,b),所以最后給d賦值為gcd的值。若d為1,說明存在這樣的x,否則不存在。

 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<stack>
 8 #include<map>
 9 #include<set>
10 #include<vector>
11 #include<deque>
12 #include<iostream>
13 using namespace std;
14 typedef long long  LL;
15 const int N = 100009;
16 
17 void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
18 {
19     if(b==0)
20     {
21         x=1;
22         y=0;
23         d=a;
24         return ;
25     }
26     else
27     {
28         exgcd(b,a%b,d,x,y);
29         LL mid=x;
30         x=y;
31         y=mid-a/b*y;
32     }
33 
34     return ;
35 }
36 LL inv(LL a, LL b)
37 {
38     LL x,y,d;
39     exgcd(a,b,d,x,y);
40     return d == 1 ? (x+b)%b : -1;
41 
42 }
43 int main()
44 {
45     LL a,p;
46     scanf("%lld%lld",&a,&p);
47     printf("%lld\n",inv(a,p));
48     return 0;
49 }
View Code

 

4、遞推打表

  令 a*x + b = p.

  b * inv[b] ≡ 1 (mod p) , 將 b 替換為 p - a*x

  (p - a * x) * inv[b] ≡ 1(mod p) ,即 p * inv[b] - (a * x * inv[b] ) ≡ 1(mod p)

  因為 p mod p 等於零, 所以上式變為 -(a * x * inv[b]) ≡ 1(mod p)

  觀察 a * x + b = p 得 , 在計算機中 a = p/x , b = p%x .

  故 - (p/x * inv[p % x] * x) ≡ 1(mod p)

  因此  -p/x *inv[p % x] ≡ inv[x] (mod p)    

  

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<stack>
 8 #include<deque>
 9 #include<iostream>
10 using namespace std;
11 typedef long long  LL;
12 const int N = 100009;
13 
14 int inv[N];
15 int main()
16 {
17     int i,p,j,n;
18     scanf("%d%d",&n,&p);
19     inv[1]=1;
20     for(i=2;i<=n;i++)
21         inv[i] = LL(p-p/i)*inv[p%i]%p;
22     for(i=2;i<=n;i++)
23         printf("%d %d \n",i,inv[i]);
24 
25     return 0;
26 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM