欧几里得算法及其扩展学习笔记

欧几里得算法

在欧几里得著的《几何原本》里面,有用线段的划分来讲解这个数学方法的,这里我们从代数而不是几何上来讲,并且侧重于算法OI竞赛。

欧几里得算法( g c d gcd gcd),又称辗转相除法,可以用来快速计算两个整数的最大公约数,并有许多扩展应用。


下面我们来看公式:
g c d ( n , m ) = g c d ( m , n   m o d   m ) gcd(n,m)=gcd(m,n\ \rm mod\ m) gcd(n,m)=gcd(m,n mod m)

我们可以简单的证明一下这个公式的正确性:
我们令 g = g c d ( n , m ) g=gcd(n,m) g=gcd(n,m),那么显然 g ∣ n , g ∣ m g|n,g|m gn,gm a ∣ b a|b ab表示 a a a b b b的因子)。又因为 n   m o d   m = n − m × ⌊ n m ⌋ n\ \rm mod\ m=n-m\times \lfloor\frac{n}{m}\rfloor n mod m=nm×mn,那么我们可以将 n , m n,m n,m写为 n = k 1 g , m = k 2 g n=k_1g,m=k_2g n=k1g,m=k2g,那么 n   m o d   m = n − m × ⌊ n m ⌋ = k 1 g − k 2 g ⌊ k 1 g k 2 g ⌋ = g ( k 1 − k 2 ⌊ k 1 g k 2 g ⌋ ) n\ \rm mod\ m=n-m\times \lfloor\frac{n}{m}\rfloor=k_1g-k_2g\lfloor\frac{k_1g}{k_2g}\rfloor=g\left(k_1-k_2\left\lfloor\frac{k_1g}{k_2g}\right\rfloor\right) n mod m=nm×mn=k1gk2gk2gk1g=g(k1k2k2gk1g),而 ( k 1 − k 2 ⌊ k 1 g k 2 g ⌋ ) \left(k_1-k_2\left\lfloor\frac{k_1g}{k_2g}\right\rfloor\right) (k1k2k2gk1g)肯定为整数,所以 g ∣ ( n   m o d   m ) g|(n\ \rm mod\ m) g(n mod m),那么显然 g ∣ g c d ( m , n   m o d   m ) g|gcd(m,n\ \rm mod\ m) ggcd(m,n mod m),(因为 g g g n , m n,m n,m的因子)。接下来我们令 g ^ = g c d ( m , n   m o d   m ) \hat g=gcd(m,n\ \rm mod\ m) g^=gcd(m,n mod m),那么显然有 g ^ ∣ g \hat g|g g^g,又因为前面我们可以得知 g ∣ g ^ g|\hat g gg^,所以就有 g = g ^ g=\hat g g=g^,那么 g c d ( n , m ) = g c d ( m , n   m o d   m ) gcd(n,m)=gcd(m,n\ \rm mod\ m) gcd(n,m)=gcd(m,n mod m)

所以代码就简单啦!
递归边界为 m = 0 m=0 m=0时,因为模数不能为0,所以此时就可以直接返回 n n n

int gcd(int n,int m){
	if(!m) return n;
	else return gcd(m,n%m); 
}//也可以用自带的__gcd(n,m);

扩展欧几里得算法

  • 前置

  • 裴蜀定理(贝祖定理)

内容:对于一个系数为整数( a , b , c a,b,c a,b,c为整数)的二元一次方程 a x + b y = c ax+by=c ax+by=c,若其存在整数解,当且仅当 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c
用处:判断一个上述的二元一次方程是否有整数解。

简单的证明:
我们令 g = g c d ( a , b ) g=gcd(a,b) g=gcd(a,b),同样的我们可以将 a , b a,b a,b写成 a = k 1 g , b = k 2 g a=k_1g,b=k_2g a=k1g,b=k2g,那么显然 a x + b y = g ( k 1 x + k 2 y ) ax+by=g(k_1x+k_2y) ax+by=g(k1x+k2y),所以 g ∣ ( a x + b y ) g|(ax+by) g(ax+by)

所以当 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c时必然有整数解,下面我们将在扩展欧几里得算法讲解给出证明,及其整数解的求法。


正题

  • Exgcd

a x + b y = c ax+by=c ax+by=c c ∣ g c d ( a , b ) c|gcd(a,b) cgcd(a,b)前提下是否一定有整数解呢?

因为有了前提,所以我们可以将原式写成 a x + b y = k ⋅ g c d ( a , b ) ax+by=k\cdot gcd(a,b) ax+by=kgcd(a,b),由于 k k k为整数,那么如果 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)有整数解,那么原式一定有整数解(倍数关系),那么只需证明并求出 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的一组特殊解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),然后所有的解都可以表示出来(原来的解就是现在解的 k k k倍)。

所以现在我们只需证明 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)有解即可。

通过 g c d gcd gcd的递推式可知,我们如果的到如下式子的一组解:
b x + ( a   m o d   b ) y = g c d ( b , a   m o d   b ) bx+(a\ \rm mod\ b)y=gcd(b,a\ \rm mod\ b) bx+(a mod b)y=gcd(b,a mod b)
令解为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),那么就有如下推导:
a x + b y = b x 1 + ( a   m o d   b ) y 1 ax+by=bx_1+(a\ \rm mod\ b)y_1 ax+by=bx1+(a mod b)y1
= b x 1 + ( a − ⌊ a b ⌋ × b ) y 1 =bx_1+(a-\left\lfloor\frac{a}{b}\right\rfloor\times b)y_1 =bx1+(aba×b)y1
= a y 1 + ( x 1 − ⌊ a b ⌋ y 1 ) b =ay_1+(x_1-\left\lfloor\frac{a}{b}\right\rfloor y_1)b =ay1+(x1bay1)b
一个小引理当 a x + b y = a z + b k ax+by=az+bk ax+by=az+bk,必然 x , y x,y x,y有一组解为 x = z , y = k x=z,y=k x=z,y=k
a x + b y = a y 1 + ( x 1 − ⌊ a b ⌋ y 1 ) b ax+by=ay_1+(x_1-\left\lfloor\frac{a}{b}\right\rfloor y_1)b ax+by=ay1+(x1bay1)b
所以有一组解为 x = y 1 , y = x 1 − ⌊ a b ⌋ y 1 x=y_1,y=x_1-\left\lfloor\frac{a}{b}\right\rfloor y_1 x=y1,y=x1bay1,而这个解显然一定会满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)。所以我们不仅证明了它一定有解,还构造出了解的样子和求法。
代码就是这样的:

int exgcd(int a,int b,int &x,int &y){
	if(!b){x=1;y=0;return a;}
	else {int now=exgcd(b,a%b,y,x);y-=x*(a/b);return now;}
}	

递归边界显然就是当 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的时候, b = 0 b=0 b=0,显然 g c d ( a , b ) gcd(a,b) gcd(a,b)不合法,所以我们就令 g c d ( a , 0 ) = a gcd(a,0)=a gcd(a,0)=a,那么原来方程就变为 a x = a ax=a ax=a,显然 x = 1 , y = 0 x=1,y=0 x=1,y=0

辗转相减的用途

既然有更快的辗转相除,那么辗转相减有什么用呢?
我们知道 g c d ( a , b ) = g c d ( a , b − a ) gcd(a,b)=gcd(a,b-a) gcd(a,b)=gcd(a,ba),那么容易推广而知 g c d ( a 1 , a 2 , a 3 , ⋯   , a n ) = g c d ( a 1 , a 2 − a 1 , a 3 − a 2 , ⋯   , a n − a n − 1 ) gcd(a_1,a_2,a_3,\cdots ,a_n)=gcd(a_1,a_2-a_1,a_3-a_2,\cdots,a_n-a_{n-1}) gcd(a1,a2,a3,,an)=gcd(a1,a2a1,a3a2,,anan1),那么对于一个序列 a a a的区间 g c d gcd gcd,我们可以通过差分的方式快速维护。
题目:bzoj 5028 小Z的加油店

应用

  • 求乘法逆元

因为我们可以发现,逆元式子 a x ≡ 1 (   m o d   m ) ax\equiv 1(\ \rm mod\ m) ax1( mod m) x x x为逆元,当 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,它可以写成 a ⋅ x = 1 + b ⋅ m a\cdot x=1+b\cdot m ax=1+bm,也就是 a ⋅ x + ( − b ) ⋅ m = 1 a\cdot x+(-b)\cdot m=1 ax+(b)m=1,因为 g c d ( a , m ) ∣ 1 gcd(a,m)|1 gcd(a,m)1,所以我们用扩展欧几里得算法求出这个方程的一组解,其中的 x x x便是它的逆元。友链-逆元求法

  • 求方程的一组解(基本操作)

  • 辗转相除法神奇用法:求以下式子
    ∑ i = 1 n ⌊ i × p q ⌋ \sum_{i=1}^{n}\left\lfloor\frac{i\times p}{q}\right\rfloor i=1nqi×p
    具体为转换成三角形求内部整点个数。

  • 题目1

  • 题目2

推荐这个讲解的友链文章IN


  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值