1. 扩展欧几里得算法
扩展欧几里得算法用于求解这样一个问题:给定两个非零整数 (a) 和 (b) ,求一组整数解 ((x,y)) 使得 (ax+by = gcd(a,b)) 成立。
易知:
下面说明求解过程。
所以设:
因此有:
又因为(/
表示整除):
所以:
所以:
重复进行以上步骤,到达递归边界时必然可以得一组解。
回到原式 (ax+by = gcd(a,b)) ,可得到递归边界:
when b=0: ax = gcd(a,0) = a
so: x=1, y=random
代码实现:
//solve: ax + by = gcd(a,b)
int extGcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
// the equation has more than one solution
// here, y can be a random val, which decide {x,y} at the last
x = 1, y = (int)random() % 10;
return a;
}
int gcd = extGcd(b, a % b, x, y);
int t = y;
y = x - (a / b) * y;
x = t;
return gcd;
}
下面继续探讨如何得出 ax+by=gcd(a,b)
的所有解。
先说结论:
下面看求解过程。
设新的解为 (x_0+s_1) 和 (y_0 - s_2) :
显然,(frac{b}{gcd(a,b)}) 和 (frac{a}{gcd(a,b)}) 是互质的(没有大于 1 的公约数)。
所以取::
其中,(K) 是任意的整数。
那么问题又来了,方程中的 (x) 的最小非负整数解是什么呢?
从通解式 (x' = x_0 + frac{b}{gcd(a,b)}K) 上看,应当是 (x' \% frac{b}{gcd(a,b)} = x_0 \% frac{b}{gcd(a,b)}) 。
但是由于在递归边界时,(y) 可以取任意值,所得的特解 (x_0) 可能为负,不能保证 (x_0 \% frac{b}{gcd(a,b)}) 是非负的。
如果 (x_0 \% frac{b}{gcd(a,b)}) 是负数,那么其取值范围是:
所以,(x) 的最小非负整数解为:
综合一下,也就是:
2. ax+by=c求解
(ax+by=c) 有解的充要条件是 (c \% gcd(a,b) == 0) 。
如果 (ax+by=gcd(a,b)) 有一组解为:((x_0,y_0)),即:
两边同乘以 (frac{c}{gcd(a,b)}):
所以:
是方程 (ax+by=c) 的一个特解。
同理可得:
所以,通解为:
3. 同余式 ax ≡ c (MOD m) 求解
首先解释何为「同余式」,给定整数 (a) 和 (b) ,如果说二者「模 (m) 同余」,即满足:(a\%m == b\%m),
(或者是满足 ((a-b)\%m==0) )。
显然,每个整数各自与 ([0,m)) 内的唯一整数满足同余关系。
现在需要求解的问题是:同余式 (ax = c quad (MOD quad m)) 的解。
由同余式的定义,可得:
那么我们设:
令 (y = -y),可得:
使用上面第二小节的结论可得:
1. 如果 (c \% gcd(a,m) eq 0) ,则同余式 (ax=c(MODquad m)) 无解。
2. 如果 (c\%gcd(a,m)=0),那么设 (ax_0+my_0 = gcd(a,m)) ,则有:
4. 逆元求解以及 (b/a)%m 计算
本文的最后一个问题:设 (a,m) 是整数,求 (a) 模 (m) 的逆元。
首先解释一下,何为「模 (m) 的逆元」:如果 (a,b) 满足:(a*b = 1(MOD quad m)),那么我们就说 (a,b) 互为模 (m) 的逆元。
易知,逆元还有以下等价定义:
那逆元到底有什么用呢?当我们计算 ((a*b)\%m) 时,编程实现时为了防止溢出会计算其等价式:(((a\%m)*(b\%m))\%m) 。但是计算 ((b/a)\%m) 时,该编程方法就无能为力了。
如果可以找到 (a) 模 (m) 的逆元 (x),即:(a*x=1(MOD quad m)),那么:
要求解 (x),实质上就是求解:
根据第三小节的结论:
1. 如果 (1\%gcd(a,m) eq0) ,即 (gcd(a,m) eq1),即 (a,m) 互质,无解。
2. 如果 (gcd(a,m)=1),那么 (ax equiv 1(MOD quad m)) 在 (0,m) 上有唯一解:
求解 (ax equiv 1(MOD quad m)),实质上是:
使用第一小节的扩展欧几里得算法,可得 (x_0) ,最后最小非负数解就是逆元:
cpp代码:
int inverse(int a, int m)
{
int x, y;
int gcd = extGcd(a, m, x, y);
return (x % m + m) % m;
}
5. 费马小定理
费马小定理:
设 (m) 是素数 ,且 (a\%m eq 0),那么 (a^{m-1} equiv 1(MOD quad m)) 。
显然 (a*a^{m-2} equiv 1 (MOD quad m)),(a^{m-2}) 就是 (a) 模 (m) 的逆元,可使用快速幂求解。