扩展欧几里得(exgcd)证明及笔记

· · 个人记录

来一发数论笔记/cy

\gcd

先放个代码: ```cpp inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } ``` 当然,还可以用系统自带的 `__gcd()` 函数,但是我的 VS 没有(哭) 那为什么可以这么写呢? $\text{gcd}$ 的证明如下: 从 $\text{gcd}(a,b)=\gcd(b,a\bmod b)$ 可以推出 $\text{gcd}(a,b)=\gcd(b,a-b)$。 设 $\gcd(a,b)$ 为 $1$ 式,则 $\gcd(b,a-b)$ 为 $2$ 式。 若 $\text{gcd}(a,b)=\gcd(b,a - b)$,则两边的约数应该相同。 那么有 $a\bmod p=b\bmod p=0$。($p$ 为约数) 那么还有 $b\bmod p=(a-b)\bmod p=0$。 从 $b\bmod p=(a-b)\bmod p=0$ 可以推出,在 $2$ 式中,$a\bmod p$ 也等于 $0$。(相减) 从 $a\bmod p=b\bmod p=0$ 可以推出, $a\bmod p=b\bmod p=(a-b)\bmod p=0$。(相减) 则两边的约数都为 $p$。 得证。 ## $\text{exgcd} ```cpp inline 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 r = x; x = y; y = r - a / b * y; } ``` 再给出简化后的模板: ```cpp inline void exgcd(int a, int b, int& x, int& y) { if (b == 0) { x = 1; y = 0; return; } exgcd(b, a % b, y, x); y -= a / b * x; } ``` $\text{exgcd}$ 是解决 $ax+by=\gcd(a,b)$ 这样一个方程组的,保证有解。 它的证明方式如下: 根据上方 $\gcd$ 证明,可以得知 $\gcd(a,b)$ 最后一定能转化成 $\gcd(a,0)$ 的情况。所以如果 $b$ 变成了 $0$,这个方程就成为了 $ax+0y=a$。最后的解就是 $x=1,y=0$。 那如果不是这种情况呢? 把 $ax+by=\gcd(a,b)$ 这个方程组进行一次递归,可变成 $bx'+(a-a/b\times b)y'=\gcd(b,a\bmod b)$(就是把 $a\ b$ 替换了一下) 从上面的式子可以推出 $bx'+by'+ay'(a/b\times b)=\gcd(b,a\bmod b)$,再进行一步结合,可变成 $ay'+b(x'-a/b\times b)$。 令 $x=y',y=x'-a/b\times b$,就可得出 $ax+by=\gcd(a,b)$。 得证。 本质上在原始模板里递归求完 `exgcd(b, a%b, x, y)` 后,对 $x$ 和 $y$ 进行了交换,然后再减去原本交换前得到的 $x$ 值。那么我们考虑,这两个值的交换是不是没必要? 答案是:确实。 再进行一步简化,就得到了简化后的代码。 $\text{exgcd}$ 有一道非常经典的题,就是同余方程那道题,可以试着用 $\text{exgcd}$ A 掉它。 -------- 综上是 $\text{exgcd}$ 和 $\gcd$ 的所有内容。