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

来源:互联网 发布:淘宝店铺店招全屏 编辑:程序博客网 时间:2024/06/02 03:05

欧拉定理(又称费马-欧拉定理):已知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 plaincopy
  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 plaincopy
  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 plaincopy
  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>  
0 0