初级数论第一节:欧几里得算法,扩展欧几里得算法,例题。
这是你也能看懂的数论。
欧几里得算法
首先讲一下欧几里得算法
欧几里得算法是可以在 $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])=gcd(F[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$。什么时候有空就更。
标签:frac,gcd,数论,欧几里得,times,算法,ax From: https://www.cnblogs.com/Xy-top/p/16948987.html