以下提到的数都是整数。
欧几里德算法用于求解最大公倍数,也就是辗转相除法。其结论非常简洁,对任意整数 a a 、 b b ,有:
typedef long long int llt;
llt gcd(llt a,llt b){
while( b ){
llt r = b;
b = a % b;
a = r;
}
return a;
}
递归实现更加简洁。
typedef long long int llt;
llt gcd(llt a,llt b){
return b ? gcd(b,a%b) : a;
}
实际使用时,只需注意 a a 、 b b 取负值的情况,此时gcd有可能计算出一个负数。
扩展的欧几里德算法是指对任意整数 a a 、 b b ,必然存在整数对 x x 、 y y ,使得:
扩展的欧几里德算法使用递归实现也非常简单:
llt exEuclid(llt a,llt b,llt&x,llt&y){
if ( 0 == b ){
return x=1,y=0,a;
}
llt r = exEuclid(b,a%b,x,y);
llt t = x;
x = y, y = t - a/b*y;
return r;
}
迭代实现稍微复杂一点点。
typedef long long int llt;
llt exEuclid(llt a,llt b,llt&x,llt&y){
llt x0 = 1, y0 = 0;
llt x1 = 0, y1 = 1;
x = 0; y = 1;
llt r = a % b;
llt q = ( a - r ) / b;
while( r ){
x = x0 - q * x1;
y = y0 - q * y1;
x0 = x1; y0 = y1;
x1 = x; y1 = y;
a = b; b = r; r = a % b;
q = ( a - r ) / b;
}
return b;
}
使用扩展的欧几里德算法可以很方便的求出乘法逆元。如果 a a 、 b b 的乘积对 p p 的余数为1,则称 b b 在模 p p 的意义下是 a a 的逆元。显然逆元是相互的。对任意非零 a a 当且仅当 a,p a , p 互质, a a 的逆元存在。
已知 a,p a , p ,求 x x ,使得 a⋅x≡1(modp) a ⋅ x ≡ 1 ( m o d p ) 成立。
原方程等价于 ax+py=1 a x + p y = 1 ,如果 a,p a , p 互质,则可以使用扩展的欧几里德算法求出 x x 。
//returns the inverse of a mod p satisfied with 1 == ax%p
//it will be success only when a and p are co-prime
inline llt inv(llt a,llt p){
llt x,y;
llt r = exEuclid(a,p,x,y);
if ( r != 1 ) return 0;
x = x % p;
if ( x < 0 ) x += p;
return x;
}