[算法笔记] 扩展欧几里得算法
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) \neq 0\) ,则同余式 \(ax=c(MOD\quad 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)\neq0\) ,即 \(gcd(a,m)\neq1\),即 \(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 \neq 0\),那么 \(a^{m-1} \equiv 1(MOD \quad m)\) 。
显然 \(a*a^{m-2} \equiv 1 (MOD \quad m)\),\(a^{m-2}\) 就是 \(a\) 模 \(m\) 的逆元,可使用快速幂求解。