拓展欧几里得
拓展欧几里得
在拓展欧几里得定理之前,先介绍以下贝祖定理:
如果方程式 \(ax + by = m\) 成立,那么 \(gcd(a, b) | m\)
显然,我们可以把原方程式写作:\(m = k1 *g * x + k2 * g * y = g(k1 * x + k2 * y)\)
根据贝祖定理,如果有 \(ax + by = 1\) ,那么 \(gcd(a, b) = 1\), 即 \(a\) 与 \(b\) 互质。
我们可以使用著名的辗转相除法算出来 \(gcd(a, v=b)\) :
int gcd (int a, int b)
{
return b ? gcd(b, a % b) : a;
}
拓展欧几里得
给出 \(ax + by = m\) ,如何求出他的一组解?
根据贝祖定理,只要我们求出 \(ax + by = gcd(a, b)\) 即可,由于 \(gcd(a, b) | m\) ,所以可以求出原式的一组因子,只需要乘上 \(m / gcd(a, b)\) 即为原式的一组解。
那么问题就转化为了,求 \(ax + by = gcd(a, b)\) 的一组 \((a, b)\) 。
\(gcd(a, b)\) 可以用欧几里得辗转相除求出,而 \(a, b\) 可以在求的过程中得出。
假设我们到达了终点,此时 \(a = gcd(a, b), b = 0\) ,那么有 \(x = 1, y = 0\) 。
由于\(gcd(a, b)\) 是递归的,当我们想要求得 \(ax + by = m\) 时,我们已经求出了 \(bx + (a \% b)y = m\) 的一组解。
\(a \% b = a - \lfloor \dfrac a b \rfloor * b\)
把已有的式子化作:\(bx + (a - \lfloor \dfrac a b \rfloor * b)y = m\)
那么,可以得到:\(ay + b(x - \lfloor \dfrac a b \rfloor * y) = m\)
所以我们发现,如果从上一层状态推下来,那么:\(x = y, y = x - \lfloor \dfrac a b \rfloor * y\)
Code
int exgcd (int a, int b, int & x, int & y)
{
if (!b) return x = 1, y = 0, a;
int r = exgcd(b, a % b, x, y);
tie(x, y) = make_tuple(y, x - (a / b) * y);
return r;
}
由于 \(ax + by \equiv m \pmod p\) 有无穷多组,而我们只计算出了一种,那么如何得到其他解?
假设我们得到解为 \(x_0, y_0\) ,还有另外一组解为 \(x_1, y_1\) ,那么可以得到:
\(ax_0 + by_0 \equiv m \pmod p\)
\(ax_1 + by_1 \equiv m \pmod p\)
两个柿子相减,得到 \(a(x_0 - x_1) \equiv -b(y_0 - y_1) \pmod p\)
两边同时除以 \(gcd(a, b)\) ,有 \(a / gcd(a, b) (x_0 - x_1) \equiv -b / gcd(a, b)(y_0 - y_1) \pmod p\)
此时 \(a / gcd\) 与 \(b / gcd\) 互质,所以一定有 \(a / gcd(a, b) | (y_0 - y_1), b / gcd(a, b) | (x_0 - x_1)\)
我们记 \(x_1 = x_0 + k * \dfrac{b}{gcd(a, b)}\) ,同理 \(y_1 = y_0 + k * \dfrac{a}{gcd(a, b)}\) 。
欧几里得用途
求逆元
\(a * a^{-1} \equiv 1 \pmod p\) ,可以写成 \(a * a^{-1} \equiv kp + 1 \pmod p\) ,
这样,我们就可以得到柿子 : \(a * a^{-1} + kp \equiv 1 \pmod p\) 。
这就是拓展欧几里得公式,由于 \(a, p\) 都已知,只需要用拓展欧几里得算出 \((a^{-1}, k)\) 即可。
注意拓展欧几里得可以计算 \(p\) 与 \(a\) 非互质情况下的逆元,而欧拉定理不能算出。