欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。
gcd(a,b)由递推所得,自然需要初始值和递推式。
1. a = b , b = a%b 这个递推式由公理 gcd(a,b)=gcd(b,a mod b) 所得。
证明:gcd(a,b)=gcd(b,a%b)
(a>b)设a = k*b + c, 则 a % b = c; (设 d为a,b的公约数), 则 a/d,b/d都为整数;因为 c = a – k*b,则c/d = a/d – k*b/d,所以c/d 一定为整数 ,得到 d为b,a%b的公约数或为a,a%b的公约数。那么a,b的所有公约数即为b,a%b的公约数,所以 gcd(a,b)=gcd(b,a%b)
2. 初始值:b = 0 时 ,最大公约数为a。
证明:根据递推式,往上推一步,gcd(a,b) = gcd(b,a%b),则a % b = 0
当a % b = 0时,其最大公约数即为b。因为a是b的倍数时,自然b为最大公约数。
int gcd(int a,int b){
if(!b) return a;
else return gcd(b,a%b);
}
扩展欧几里得算法,求不定方程。
对于不定方程ax+by=c,求满足其方程的整数解。
扩展欧几里得能对ax+by=gcd(a,b)计算所有x,y的解,只有满足c%gcd(a,b)==0时,ax+by=c才有解,当然解由ax+by=gcd(a,b)计算结果 * (c/gcd(a,b))得到。
递推式原理:对于不定方程有: ax1+by1 = gcd(a,b) ; 也可以替换未知数 bx2+(a%b)y2 = gcd(b,a%b); 由欧几里得所证的定理 gcd(a,b) = gcd(b,a%b); 那么ax1+by1 = bx2+(a%b)y2; 将a%b = a-a/b*b, 那么ax1+by1 = ay2+b(x2-a/b*y) , 有恒等式 x1 = y2 ; y1 = x2-a/b*y。
得到递推的等式,我们需要知道其初始点。当b=0时,gcd(a,b)=a,此时x=1,y=0。
计算得到ax+by=c的解,只是ax+by=c的其中的一个解,而其他值满足:
x(i) = x + b/Gcd(a, b) * t
y(i) = y - a/Gcd(a, b) * t (其中t为任意整数,两者需同时进行)
【ps.可以自行代入a,b验证】
int ExGCD(int a, int b, int& x, int& y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
int d = ExGCD(b, a%b, x, y);
int temp = x;
x = y;
y = temp - a/b*y;
return d;
}
//d为gcd(a,b), x , y得到的是c = gcd(a, b)时的值。
扩展欧几里得算法,求同余方程。
同余方程 ax≡b (mod n)对于未知数 x 求解。
其实求解方程 ax≡b (mod n) 就相当于求解方程 ax+ ny= b, (x, y为整数)
1. 扩展欧几里得算法,求模的逆元就相当于ax+ny = 1,要保证x为正整数。
2. 当p为质数时候用费马小定理x^(p-1)≡1(%p),x*x^p-2≡1(%p),x^p-2为逆元。快速幂求逆元。
3. 当p为质数,线性求逆元。i^(-1) ≡ 1(%p) , 设 p = ka+b,则 ka+b ≡ 0(%p),两边同乘a^(-1)b^(-1),则
a^(-1) ≡ -k*b^(-1) (%p),则 a^(-1) = (-p/a * (p%a)^(-1)) (%p)。
也就是说a对p的逆元可以由(p%a)对p的逆元推出。如下:
//一个快速求乘法逆元的模版。。。
inv[0]=0,inv[1]=1;
for(int i=2;i<=N+10;i++)
{
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
// i是代表x,mod%i是代表a;
}