exgcd(扩展欧几里得)学习笔记
前置芝士
- 基础的模、整数运算;
- gcd 的求法,即 gcd(a,b)=gcd(b,amodb);
- 裴蜀定理,二元一次方程方程 ax+by=c 有解的充要条件是 gcd(a,b)∣c;
正文部分
exgcd 用于求出二元一次方程 ax+by=c 的一组特解。
首先根据裴蜀定理,可以先判掉无解的情况。这样我们可以先计算 ax+by=gcd(a,b) 这个方程的解,再乘上 gcd(a,b)c。
既然是 exgcd,那我们考虑 gcd 是怎么做的,即缩小问题规模,把 gcd(a,b) 转化为 gcd(b,amodb) 递归求解。
同样的思路,我们把方程转化为 bx+(amodb)y=gcd(b,amodb) 递归求解。所以现在的问题是,我们知道一个方程:
bx+(amodb)y=gcd(b,amodb)
的一组解 {x2,y2},求
ax+by=gcd(a,b)
的一组解 {x1,y1}。因为
gcd(a,b)=gcd(b,amodb)
,所以
bx2+(amodb)y2=gcd(a,b)
然后用拆开取模的小技巧可以得到:
bx2+(a−b⌊ba⌋)y2=gcd(a,b)
继续化简:
bx2+ay2−b(⌊ba⌋y2)=gcd(a,b)
⇒ay2+b(x2−⌊ba⌋y2)=gcd(a,b)
最后得到:
\begin{cases}
\begin{align}
&x_1 = y_2\\
&y_1 = \left (x_2 - \left \lfloor \dfrac{a}{b} \right \rfloor \right )
\end{align}
\end{cases}
考虑边界,当 b=0 时,x=1,y=0,时间复杂度与 gcd 相同, Θ(log n)。
CODE
void exgcd(int a, int b, int &x, int &y) {
if (b == 0) {x = 1, y = 0; return;};
exgcd(b, a % b, x, y);
int t = y; y = x - (a / b) * y, x = t;
}
参考:OI Wiki。