求逆元

来源:互联网 发布:相似矩阵 编辑:程序博客网 时间:2024/06/07 08:51

比如:  (8/2)%5 
我们求a*b*c*d*e*f*g..../z 前面乘积部分LL存不下所以要一边mod一边乘
最后处理到除z时,不一定能除尽
比如前面那个例子,8/5=3,3除不尽2就乘以2%5的逆元在%5
2%5的逆元=2^(5-2)=8 这是计算逆元的一种方法,后面讲。还有一直哦你方法是扩展欧几里德算法也是后面详细讲。
(3*8)%5=4=4%5

===

在计算(a/b)%Mod时,往往需要先计算b%Mod的逆元p(b有逆元的条件是gcd(b,Mod)==1,显然素数肯定有逆元),然后由(a*p)%Mod得结果c。这里b的逆元p满足(b*p)%Mod=1。先来简单证明一下:
(a/b)%Mod=c;    (b*p)%Mod=1;    ==》   (a/b)*(b*p) %Mod=c;    ==》    (a*p)%Mod=c;


从上面可以看出结论的正确性,当然这里b需要是a的因子。接下来就需要知道根据b和Mod,我们怎么计算逆元p了。扩展欧几里德算法,大家应该都知道,就是已知a、b,求一组解(x,y)使得a*x+b*y=1。这里求得的x即为a%b的逆元,y为b%a的逆元(想想为什么?把方程两边都模上b或a看看)。调用ExtGcd(b,Mod,x,y),x即为b%Mod的逆元p。
 求b%Mod的逆元p还有另外一种方法,即p=b^(Mod-2)%Mod,因为b^(Mod-1)%Mod=1(这里需要Mod为素数)。


以上来自:http://hi.baidu.com/zhanggmcn/item/ef4dadceb4fb993e449416e7

如例子    3/2%5=4; 2*3%5=1  ==>  (3/2)*(2*8)%5=4  ==> (3*8)%5=4

===

关于扩展欧几里德:
首先扩展欧几里德主要是用来与求解线性方程相关的问题,所以我们从一个线性方程开始分析。现在假设这个线性方程为a*x+b*y=m,如果这个线性方程有解,那么一定有gcd(a,b) | m,即a,b的最大公约数能够整除m(m%gcd(a,b)==0)。证明很简单,由于a%gcd(a,b)==b%gcd(a,b)==0,所以a*x+b*y肯定能够整除gcd(a,b),如果线性方程成立,那么就可以用m代替a*x+b*y,从而得到上面的结论,利用上面的结论就可以用来判断一个线性方程是否有解。
      那么在a*x+b*y=m这个线性方程成立的情况下,如何来求解x和y呢?
      1.令a1=a/gcd(a,b),b1=b/gcd(a,b),m1=m/gcd(a,b)。如果我们能够首先求出满足a*x1+b*y1=gcd(a,b)这个方程的x1和y1,那么x=x1*m1,y=y1*m1就可以求出来了。由欧几里德算法gcd(a,b)=gcd(b,a%b),所以a*x1+b*y1=gcd(a,b)=gcd(b,a%b)=b*x2+(a%b)*y2,现在只要做一些变形就可以得到扩展欧几里德算法中的用到的式子了。令k=a/b(商),r=a%b(余数),那么a=k*b+r。所以r=a-k*b,带入上式,得到a*x1+b*y1=b*x2+(a-(a/b)*b)y2=a*y2+b*(x2-(a/b)*y2) => x1=y2,y1=x2-(a/b)*y2。有了这两个式子我们就知道了在用欧几里德求最大公约数的时候,相应的参数x,y的变化。现在再回过头来看一下扩展欧几里德算法的代码就很好理解了,实际上扩展欧几里德就是在求a和b的最大公约数的同时,也将满足方程a*x1+b*y1=gcd(a,b)的一组x1和y1的值求了出来。下面代码中突出的部分就是标准的欧几里德算法的代码。

[cpp] view plain copy
  1. __int64 exGcd(__int64 a,__int64 b,__int64 &x,__int64 &y){  
  2.     if(b==0){  
  3.         x=1;  
  4.         y=0;  
  5.         return a;  
  6.     }  
  7.     __int64 g=exGcd(b,a%b,x,y);  
  8.     __int64 temp=x;  
  9.     x=y;  
  10.     y=temp-(a/b)*y;  
  11.     return g;  
  12. }  


     2.那么x,y的一组解就是x1*m1,y1*m1,但是由于满足方程的解无穷多个,在实际的解题中一般都会去求解x或是y的最小正数的值。以求x为例,又该如何求解呢?还是从方程入手,现在的x,y已经满足a*x+b*y=m,那么a*(x+n*b)+b*(y-n*a)=m显然也是成立的。可以得出x+n*b(n=…,-2,-1,0,1,2,…)就是方程的所有x解的集合,由于每一个x都肯定有一个y和其对应,所以在求解x的时候可以不考虑y的取值。取k使得x+k*b>0,x的最小正数值就应该是(x+k*b)%b,但是这个值真的是最小的吗??如果我们将方程最有两边同时除以gcd(a,b),则方程变为a1*x+b1*y=m1,同上面的分析可知,此时的最小值应该为(x+k*b1)%b1,由于b1<=b,所以这个值一定会小于等于之前的值。在实际的求解过程中一般都是用while(x<0)x+=b1来使得为正的条件满足,为了更快的退出循环,可以将b1改为b(b是b1的倍数),并将b乘以一个倍数后再加到x上。


以上转自:http://cie.xtu.edu.cn/acmfan_cn/viewthread.php?tid=844

===

[cpp] view plain copy
  1. 扩展欧几里德求逆元模板:  
  2. #include<iostream>  
  3. #define __int64 long long  
  4. using namespace std;  
  5. //举例 3x+4y=1 ax+by=1  
  6. //得到一组解x0=-1,y0=1 通解为x=-1+4k,y=1-3k  
  7. inline __int64 extend_gcd(__int64 a,__int64 b,__int64 &x,__int64 &y)//ax+by=1返回a,b的gcd,同时求的一组满足题目的最小正整数解  
  8. {  
  9.     __int64 ans,t;  
  10.     if(b==0){x=1;y=0;return a;}  
  11.     ans=extend_gcd(b,a%b,x,y);t=x;x=y;y=t-(a/b)*y;  
  12.     return ans;  
  13.     }  
  14. //(a/b)%mod=c 逆元为p,(p*b)%mod=1  
  15. //(a/b)*(p*b)%mod=c*1%mod=c  
  16. // (p*b)%mod=1 等价于 p*b-(p*b)/mod*mod=1其中要求p,b已知 等价于 ax+by=1  
  17. //其中x=p(x就是逆元),y=p/mod,a=b,b=b*mod 那么调用extend_gcd(b,b*mod,x,y)即可求(a/b)%mod的逆元等价于a*p%mod  
  18. int main()  
  19. {  
  20.     __int64 a,b,x,y,c,gcd,mod,p;//ax+by=c  
  21.     while(cin>>a>>b>>c)  
  22.     {  
  23.           gcd=extend_gcd(a,b,x,y);  
  24.           cout<<x<<"  "<<y<<endl;  
  25.           if(c%gcd){cout<<"无解!"<<endl;continue;}  
  26.           cout<<"x="<<x*c/gcd<<" y="<<y*c/gcd<<endl;  
  27.           }  
  28.     return 0;  
  29.     }  


转自:http://hi.baidu.com/foreverlin1204/item/5e3da7d437b4d290270ae76c

===


根据大连I题和大神代码..再改了一个一个模板:

贴上模板:


[cpp] view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. int x,y,rev;  
[cpp] view plain copy
  1. void extend_Euclid(int a, int b)  
  2. {  
  3.     if(b==0)  
  4.     {  
  5.         x = 1;  
  6.         y = 0;  
  7.         return;  
  8.     }  
  9.     extend_Euclid(b, a%b);  
  10.     int t = x;  
  11.     x = y;  
  12.     y = t - a/b*y;  
  13. }  
  14.   
  15.   
  16. int main()  
  17. {  
  18.     //b%mod的逆元  
  19.     int b,mod;  
  20.     while(cin>>b>>mod){  
  21.        // x=0;y=0;  
  22.         extend_Euclid(b,mod);  
  23.         cout<<(x%mod+mod)%mod<<endl;  
  24.     }  
  25.     return 0;  
  26. }  

0 0
原创粉丝点击