exgcd 学习笔记
扩展欧几里得算法简称扩欧或 exgcd。它是求解最大公约数的欧几里得算法的扩展,用于求解二元一次不定方程的重要算法,也是数论的重要学习内容之一。
1.1 算法介绍
我们规定 \(a, b> 0\),其他情况类似,读者可自行推导,令 \(d = \gcd(a,b)\)。
在解方程之前,我们先要判定一个方程是否有解,我们可以利用下面的定理:
裴蜀定理:二元一次不定方程 \(ax + by = c\) 有解的充要条件为 \(d \, \vert \, c\)。
若想求解 \(ax+by=c\),我们显然只要求解 \(ax+by=d\),最后再将答案乘上 \(\dfrac{c}{d}\),由裴蜀定理可知这是整数。
回顾求解 \(\gcd(a,b)\) 的方法,我们利用恒等式 \(\gcd(a,b)=\gcd(b, a \bmod b)\) 递归求解,利用这一思想,我们假设我们已经得到了 \(bx'+(a \bmod b)y' = d\) 的一组特解,显然可得:
容易得到:\(x = y', y = x' -\left\lfloor \dfrac{a}{b} \right\rfloor y'\),这给了我们很好的性质去递归求解方程的特解,显然当 \(a=1, b=0\) 时,方程的一组解为 \(x = 1, y = 0\),回溯计算即可,设 \(V\) 表示值域大小,时间复杂度为 \(\mathcal{O}(\log V)\),代码实现如下:
inline void exgcd(int a, int b, int &x, int &y) {
if (!b) return x = 1, y = 0, void();
exgcd(b, a % b, y, x); y -= a / b * x;
}
1.2 通解的形式和范围
对于一般的题,求出一组特解是远远不够的,所以我们要对通解进行研究,设 exgcd 求出的特解为 \(x_0\) 和 \(y_0\),则对于 \(s \in \mathbb{Z}\),容易发现通解满足下面的式子:
那么对于正整数解,我们显然可以求出 \(s\) 的范围:
由于 \(s\) 是整数,所以:
下面给出 【模板】二元一次不定方程 (exgcd) 的代码实现:
inline void exgcd(int a, int b, int &x, int &y) {
if (!b) return x = 1, y = 0, void();
exgcd(b, a % b, y, x); y -= a / b * x;
}
inline void Solve() {
int a = read(), b = read(), c = read();
int d = __gcd(a, b);
if (c % d) printf("-1\n");
else {
int x0, y0, T = c / d;
exgcd(a, b, x0, y0);
x0 *= T; y0 *= T;
int smin = floor(1.0 * (b - d * x0) / b), smax = floor(1.0 * (d * y0 - 1) / a);
if (smin > smax) {
int xmin = x0 + smin * b / d;
int ymin = y0 - smax * a / d;
printf("%lld %lld\n", xmin, ymin);
}
else {
int xmin = x0 + smin * b / d;
int xmax = x0 + smax * b / d;
int ymin = y0 - smax * a / d;
int ymax = y0 - smin * a / d;
printf("%lld %lld %lld %lld %lld\n", smax - smin + 1, xmin, ymin, xmax, ymax);
}
}
}

浙公网安备 33010602011771号