最大公约数,欧几里得算法(gcd)

对于整数而言:
若x能够整除y,则记x|y。称x为y的约数。
若m是x除y的余数,则记作x m o d mod mod y=m,或x%y=m。称x被y取模的结果为m,m为模数。或称x模y等于m。 m o d mod mod就是取模运算(取余运算)。
x|y,等价于y m o d mod mod x=0

最大公约数

若x|y,则x是y的约数。
若x|a,且x|b,则称x是a、b的公约数。
那么,所有a、b的公约数中最大的那一个,称为a、b的最大公约数(Greatest Common Divisor),记作gcd(a,b)。
一些时候简写为g,gcd,g(a,b),(a,b),…

欧几里得算法(gcd)

欧几里得算法可以快速求出两数a,b的最大公约数。
其表述如下递归式:
g c d ( a , b ) = { g c d ( b , a   m o d   b )    ( b ≠ 0 ) a                                              ( b = 0 ) gcd(a,b)=\left\{\begin{matrix} gcd(b,a \:mod\: b)\;(b\neq 0)\\ a\; \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(b=0) \end{matrix}\right. gcd(a,b)={gcd(b,amodb)(b=0)a(b=0)

证明一下:
假设此时a>=b,否则进行一轮递归之后,a>=b。
设s|a,且s|b。
则有: a = k 1 s , b = k 2 s ( k 1 , k 2 ∈ Z ) a=k_1s,b=k_2s(k_1,k2\in \mathbb{Z}) a=k1s,b=k2s(k1,k2Z)
所以: a − b = k 1 s − k 2 s = ( k 1 − k 2 ) s a-b=k_1s-k_2s=(k_1-k_2)s ab=k1sk2s=(k1k2)s
即: s ∣ a − b s|a-b sab

如果a-b仍大于等于b,把a-b看做新的a,重复上面的过程,继续用b来减它。
最终得到 s ∣ a − k ⋅ b ( k ∈ Z ) s|a-k\cdot b(k\in\mathbb{Z}) sakb(kZ),使得 a − k ⋅ b < b a-k\cdot b<b akb<b,此时 a − k ⋅ b = a    m o d    b a-k\cdot b=a\;mod\;b akb=amodb
这很显然,如果a一直减去b,直到小于b,那么必定得到除以b的余数。

也就是说 s ∣ a    m o d    b s|a\; mod\; b samodb
这就说明任意a、b的约数都是a m o d mod mod b的约数。

因为任意a、b的约数都是a m o d mod mod b的约数,因此a、b的最大公约数也是a m o d mod mod b的约数。
g c d ( a , b ) = g c d ( b , a    m o d    b ) gcd(a,b)=gcd(b,a\;mod\;b) gcd(a,b)=gcd(b,amodb)

QED.

就有了代码:

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

其中!b表示b==0.

当然也有 g c d ( a , b ) = g c d ( a , a    m o d    b ) gcd(a,b)=gcd(a,a\;mod\;b) gcd(a,b)=gcd(a,amodb)。可是这样如果b<a,就需要手动交换,代码写起来不方便,一般不采用这种形式。

你可以证明一下,a m o d mod mod b <= a 2 \frac{a}{2} 2a,这表明每递归两次,数据规模至少缩小一半。
若a、b与n的数据规模相当(同阶):欧几里得算法(gcd)的时间复杂度为O(logn)。

库中的gcd函数

在实现的时候,一般不采用手写的gcd函数。事实上,比赛的编译环境支持使用自带的gcd函数:__gcd(a,b)
__gcd(a,b)包含在algorithm库内,返回两个数的最大公约数。复杂度O(logn)。

后记

于是皆大欢喜。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值