乘法逆元的扩展欧几里得解法

【序言】正好今天BZOJ崩了(反正我上不去),我总算可以静下心来研究一些东西。乘法逆元已经不陌生了,但是平常不怎么用到(skydec整天做神题肯定很熟练了,ORZ),因此是该好好复习一下。

万一我以后忘记了,可以来看看= =。

【传送门】参考了几位大神的资料,本蒟蒻表示不胜感激

http://chhaj5236.blog.163.com/blog/static/112881081200942542255916/(真心膜拜)

http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html

http://blog.sina.com.cn/s/blog_7064e7850100yeu1.html

【扩欧的求法】经典的欧几里得算法早就烂熟于心,但是对于扩欧我原来一无所知。扩展欧几里德主要是用来与求解线性方程相关的问题。现在假设一个方程为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)。

那么以下是关于此方程的解法:

令a1=a/gcd(a,b),b1=b/gcd(a,b),P=m/gcd(a,b)。如果我们能够首先求出满足a*x1+b*y1=gcd(a,b)(即原式两边除以P)这个方程的x1和y1,那么x=x1*P,y=y1*P就可以求出来了。由欧几里德算法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的值求了出来。

【代码】

int exGcd(int a,int  b,int &x,int &y)
{
    if(b==0){x=1;y=0;return a;}
    int g=exGcd(b,a%b,x,y);
    int temp=x;x=y;
    y=temp-(a/b)*y;
    return g;
}

最后再乘上P,你懂的。这就是一组解。

【逆元】设我们要求a/b%p的值,我们可以转化为a*x%p。显然,(1/b)%p=x%p,x*b%p=1。

前提:gcd(x,b)=1.这样的话,x就存在。

如何求解a*x%n=1的方程呢?我们可以化成ax+ny=1,然后在上述gcd中带出。

【疑问】为什么网上的逆元模板都是有3个x和y的。= =

你可能感兴趣的:(算法讲解)