1.拓展欧几里得
适用于解决:给定两个非零整数 a 和 b,求一组整数解( x,y ),使得 ax + by = gcd(a , b)成立,其中 gcd(a,b) 表示 a,b 的最大公因数。
求解ax+by=gcd(a,b)的一组特解x0,y0,并返回gcd(a,b)。
代码实现:
一般:
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;
}
简洁实现:
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,y,x);
y -= a/b * x;
return g;
}
2.方程 ax + by = c 的求解
方程有解的充要条件是 c % gcd(a, b)== 0。
其通解表示为:
x = c * x0 / gcd + b / gcd * k;
y = c * y0 / gcd - a / gcd * k;
k为任意整数。
x的最小整数解:
x = (x % (b / gcd) + (b / gcd) ) % (b / gcd);
y的最小整数解:
y=(y % (a / gcd) + (a / gcd) ) % (a / gcd);
3.同余式 ax ≡ c(mod m) 求解
ax ≡ c(mod m) <–> (ax - c) % m = 0
根据同余式的定义,有(ax - c)%m = 0成立,因此存在整数 y,使得 ax - c = my成立。
移项并令y = -y 然后得到 ax + my = c.
设a,c,m 是整数,其中 m ≥ 1,则:
- [1] 若c % gcd(a,m) ≠ 0,则同余式 ax ≡ c(mod m) 无解
- [2] 若c % gcd(a,m) = 0,则同余式 ax ≡ c(mod m) 恰好有gcd(a,m)个模m意义下不同的解,且解的形式为 x‵ = x + m / gcd(a,m) * k;
其中 k = 0,1,……gcd(a,m)-1,x 是 ax + my = c 的一个解。
4.逆元的求解以及(b/a)%m 的计算
假设a,b,m是整数,m>1,且有ab ≡ 1(mod m)成立,那么就说a和b互为模m的逆元。
通俗地讲,如果两个整数的乘积模m后等于1,就称这它们互为m的逆元。
有定义知:求a模m的逆元,就是求解同余式ax ≡ c(mod m),并且**在实际使用中,一般把x的最小正整数解称之为a模m的逆元,因此下文提到的逆元默认为x的最小正整数解。显然,同余式 ax ≡ c(mod m) 是否有解取决于1%gcd(a,m)是否为0,而这等价于gcd(a,m)是否为1: - [1] 如果gcd(a,m)≠1,那么ax ≡ c(mod m)无解,a不存在模m的逆元。
- [2] 如果gcd(a,m)=1,那么ax ≡ c(mod m)在(0,m)上有唯一解。
int inverse(int a,int m){
int x,y;
int g = exgcd(a,m,x,y); //求解ax + by = 1
return (x % m + m) % m; //a模m的逆元为(x%m+m)% m
}
如果m是素数,且a不是m的倍数,可以用费马小定理来的逆元,
费马小定理:设m是素数,a是任意整数且 a mod m ≠ 0,则有 am-1 ≡ 1(mod m)
所以a * am-2 ≡ 1(mod m),即 am-2%m 是 a 模 m的逆元。
假设(b / a)% m = x,因此存在整数 k,使得b / a = km + x。等式两边同时乘以 a,得 b = kam + ax,于是b%(am) = ax。等式两边同时除于 a,得(b % (am)) / a = x,于是有(b / a) % m = (b%(am))/a成立。
因此在 a 和 m 有可能互补相素的情况下,可以使用公式(b / a) % m = (b % (am) ) / a来计算(b/a)%m的值,唯一注意的的是a和m的乘积可能会太大而溢出。