初级数论1:(扩展)欧几里得算法

初级数论第一节:欧几里得算法,扩展欧几里得算法,例题。

欧几里得算法

先来讲一下欧几里得算法

欧几里得算法是可以在 $O(\log_n)$ 时间内求解两数最大公约数的算法,简称 $\gcd$。

代码如下:

int gcd (int a, int b)
{
    if (b == 0) return a;
    return gcd (b, a % b);
}

证明一下这个算法的正确性。

$b=0$ 的时候 $a,b$ 的最大公约数就是 $a$,这个是对的。

现在需要证明 $\gcd(a,b)=\gcd(b,a\%b)$,可以再简化一点,证明 $\gcd(a,b)=\gcd(b,a-b)$。

因为$a$ 一直减 $b$ 直到 $a<b$ 最后得到的结果就是 $a\% b$

证明

设 $\gcd(a,b)=x$,那么 $a|x,b|x$。

设 $a=cx,b=dx$,$a>b$。

那么 $a-b=(c-d)\times x$,$a-b$ 也是 $x$ 的倍数。

所以 $\gcd(a,b)=\gcd(b,a-b)$

时间复杂度证明

设 $a>b$。

如果 $a>2b$,那么迭代一次之后 $a$ 会缩小到 $b$ 以内,减半。

如果 $b<a<2b$,那么第一次迭代之后变成 $b,a\%b$,此时有三种情况:

$a\%b<\frac{b}{2}$,那么下一轮 $b\%(a\%b)$ 小于 $a\%b$,即小于 $\frac{b}{2}$。

$a\%b>\frac{b}{2}$,那么下一轮 $b\%(a\%b)$ 就会等于 $b-(a\%b)$,因为 $a\%b>\frac{b}{2}$所以 $b-(a\%b)<\frac{b}{2}$。

$a\%b=\frac{b}{2}$,直接成 $0$ 了。

每一轮都减半, $log_n$ 次就成 $0$ 了。

拓展知识:

$1.gcd(a,b)$ 一般跑不满 $log_n$,只有相邻的斐波那契数列会跑满。

证明:

假设斐波那契数列的相邻两项为 $a,b$,那么$a < b < 2a$,取余相当于减。

而相减就会变成斐波那契数列的上一项,

所以用欧几里得算法求斐波那契数列的第 $x$ 项和第 $x+1$ 项的最大公约数。

时间复杂度就是 $O(x)$,而斐波那契数列的增长是 $2^n$ 不到一点,基本跑满 $O(log_n)$

$2.\gcd(F[n],F[m])=F[\gcd(n,m)]$,这个在算法竞赛中很有用。

其中,$F[n]$ 指的是斐波那契数列的第 $n$ 项

证明过程太长,此处省略 $500$ 字。

例题:$Luogu P1306$ 斐波那契公约数

扩展欧几里得算法

扩展欧几里得算法是可以在 $O(\log_n)$ 的时间内求方程 $ax+by=gcd(a,b)$ 的整数解。

简称扩欧,别名 $exgcd$。

其中,$a,b$ 已知,$\gcd(a,b)$ 可以在算的时候求。

扩展欧几里得算法是用小的解算出大的解然后回退。

终止答案

欧几里得算法的终结条件是 $b=0$,$b$ 最后一定会等于 $0$。

所以我们从 $b=0$ 的情况入手。

即 $ax+0\times y=gcd(a,0)$,$x$ 取 $1$,$y$ 按理来说取任何数都行。

但是取太大最后会爆 $longlong$,所以取 $0$。

回退

先来看一下欧几里得算法,$\gcd(a,b)$可以怎么求?

我们只要知道了 $\gcd(b,a\% b)$ 就可以求得 $\gcd(a,b)$,因为 $\gcd(a,b) = \gcd(b,a\% b)$。

扩展欧几里得算法也是这样,要想求 $ax+by=\gcd(a,b)$ 的整数解,

可以先求 $bx'+(a\%b)\times y'=gcd(b,a\% b)$ 的整数解,然后回退得到 $ax+by=\gcd(a,b)$ 的解。

我们先假设已经求得了 $bx'+(a\%b)\times y'=gcd(b,a\% b)$ 的解,这是必然的。

因为最后 $b$ 会等于 $0$,就会得到一组解,然后慢慢回退。

解的变形

首先可以发现 $\gcd(b,a\% b)=\gcd(a,b)$。

我们现在就知道了 $bx'+(a\%b)\times y=\gcd(a,b)$。尝试拆开拼出 $ax+by$。

其次,$a\% b$ 可以写成 $a-\lfloor\frac{a}{b}\rfloor\times b$。

代入进去变成 $bx'+(a-\lfloor\frac{a}{b}\rfloor\times b)\times y'=\gcd(a,b)$。

拆开变成 $bx'+a\times y' - \lfloor\frac{a}{b}\rfloor \times b\times y'=\gcd(a,b)$。

然后把和 $a$ 有关的,还有和 $b$ 有关的提出来。

得到 $ay'+b\times (x' + \lfloor\frac{a}{b}\rfloor \times y') = \gcd(a, b)$

然后我们发现这个方程不就是 $ax + by$ 的形式吗?

$x$ 就等于 $y'$,$y$ 稍麻烦一点,等于 $x' +\lfloor\frac{a}{b}\rfloor \times y'$

然后就可以回退到上一层求解了。

时间复杂度证明

不难发现,$exgcd$ 的时间复杂度只和 $a,b$ 有关,

并且 $a,b$ 每一次还是变成 $b,a\% b$,所以时间复杂度和 $gcd$ 一样。

代码:

void exgcd (int a, int b)
{
    if (b == 0)//b=0 的情况答案可以直接得到
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd (b, a%b)//否则先算 exgcd(b, a % b) 的解。
    int t = x;//现在的 x, y 是 bx + (a % b)y = gcd(a, b) 的解。
    x = y;//刚刚证明了 ax + by = gcd(a, b) 的解 x 就是上一个方程的解 y
    y = t - a / b * y;//x 已被更改,所以用临时变量 t 存储上一个方程的解 x
}

拓展:一般形式

题目里很少有要求 $ax+by=\gcd(a,b)$ 的整数解,一般都是求 $ax+by=c$ 的整数解。

这时该怎么办呢?

如果 $\gcd(a,b)|c$,那么我们在等式两边同乘以 $\frac{c}{\gcd(a,b)}$ 即可得到整数解。

否则,可以证明,该方程无整数解。

例题:

$1.iai$ 六星题 两个闹钟

$2.iai$ 五星级挑战 无尽的循环

两个闹钟

题意已经很明显了,就是一个扩欧。

设两个整数 $x,y$,使得 $ax+n=by+m$。

整理得 $ax-by=m-n$。

另 $y'=-y$,代入得 $ax+by'=m-n$

其中,$m-n$ 和 $a,b$ 都是已知的,这不就是扩欧吗?

解出来之后,$ax+n$ 或者 $-by'+m$ 都是题目要求的答案。

但是这个解有可能是负的,所以得尝试把他变成正的。

可以发现两个闹钟第一次同时响如果在 $t_1$ 时刻,那么下一次响肯定是在 $t_1+lcm(a,b)$ 时刻啦!

那么就一直加 $lcm(a,b)$ 直到都变成正的就好了。

但是会超时,用一个除法就可以了。

无尽的循环

这一道题是需要变形一下的,大家可以自己先尝试一下。

另外,注意开个 $longlong$。

简化题意

给定 $a,b,c,k$,求一个整数 $d$,使得 $a+dc\equiv b$ $(mod$ $2^k)$。

然后把同余去了,变成 $a+dc = b + e\times 2^k$。

把 $e$ 移到左边,$b$ 移到右边,得 $dc - e\times 2^k = b - a$。

其中, $c,2^k$ 已知,右边的 $b-a$ 也是已知的。

令 $a=c,x=d,b=2^k,y=e,c=b-a$,这就是一个典型的扩欧式子。$ax+by=c$

最后 $x$ 就是要求的答案,然后还需要化简一下,和两个闹钟差不多,大家可以自己去研究研究。

 

下节预告:中国剩余定理 $CRT$ 和扩展中国剩余定理 $EXCRT$。什么时候有空就更。

posted @ 2022-12-04 12:17  Xy_top  阅读(110)  评论(5编辑  收藏  举报