欧几里得算法:
- 定义:gcd 的意思是最大公约数,通常用扩展欧几里得算法求
原理:gcd(a,b)=gcd(b,a%b)
- 证明:
令 d=gcd(a,b)⇒a=m⋅d,b=n⋅d
则 m⋅d=t⋅n⋅d+a%b⇒a%b=d⋅(m−t⋅n)
gcd(b,a%b)=gcd(n⋅d,(m−t⋅n)⋅d)
令 gcd(n,m−t⋅n)=e⇒n=x⋅e,m−t⋅n=y⋅e
则 m−x⋅e⋅n=y⋅e⇒m=e⋅(x⋅n+y)
由 gcd(n,m)=1 知 gcd(e⋅(x⋅n+y),e⋅x)=1
故 e=1
故 gcd(n⋅d,(m−t⋅n)⋅d)=d 即 gcd(b,a%b)=gcd(a,b)
- 边界:
当 b = 0 时 return a
可以视为 gcd(a,0)=a ,任何数都能整除 0
也可以视为 gcd(a,b)=b ,这里的 a 和 b 是上一层的,满足 a%b=0
-
特殊情况:
当 a < b 时,a%b = a,所以在下一层 gcd(b, a%b) 中相当于把 a 与 b 交换
-
代码:
1
| int gcd(int a,int b){ return b ? gcd(b,a%b) : a;}
|
扩展欧几里得算法:
- 丢番图方程:
有一个或者几个变量的整系数方程,它们的求解仅仅在整数范围内进行。
扩展欧几里得算法研究的是形如 a⋅x+b⋅y=c 的丢番图方程的解
- 裴蜀定理:
对于正整数 a 和 b ,令 gcd(a,b)=d ,则对于任意整数 x 和 y ,都有 d∣(a⋅x+b⋅y)
证明:
令 a=n⋅d,b=m⋅d,则 a⋅x+b⋅y=d⋅n⋅x+d⋅m⋅y
显然 d∣(d⋅n⋅x+d⋅m⋅y)
- 引理:
丢番图方程 a⋅x+b⋅y=c 有解当且仅当 d∣c
对于任意整数 x 和 y ,a⋅x+b⋅y 的最小正值为 gcd(a,b)
证明:
①必要性:
由裴蜀定理,不存在整数 x 和 y ,使得 d 不整除 (a⋅x+b⋅y)
②充分性:
要证 a⋅x+b⋅y=c 有解,只需 a⋅x+b⋅y=d 有解
令对于 ∀x,y∈Z ,a⋅x+b⋅y 能得到的最小正值为 s
由裴蜀定理,d∣s ,则 d≤s
令 q=⌊sa⌋,p=a%s
则 p=a−q⋅(a⋅x+b⋅y)=a⋅(1−q⋅x)−q⋅b⋅y=a⋅(1−q⋅x)+b⋅(−q⋅y)
由 p=a%s 知 0≤p<s
又 s 为 a⋅x+b⋅y 能得到的最小正值
故 p=0 ,即 s∣a
同理,s∣b ,即 s∣d ,故 s≤d
综上,s=d
即对于 ∀x,y∈Z ,a⋅x+b⋅y 能得到的最小正值为 d
故 ∃x,y∈Z ,使 a⋅x+b⋅y=d
即 ∃x,y∈Z ,使 a⋅x+b⋅y=c
- 扩展欧几里得算法:
通常将求解 a⋅x+b⋅y=c 转化为求解 a⋅x+b⋅y=gcd(a,b) ,得解后乘上 gcd(a,b)c 即可
令
a⋅x1+b⋅y1=gcd(a,b)
b⋅x2+(a%b)⋅y2=gcd(b,a%b)
由 gcd(a,b)=gcd(b,a%b) 知
a⋅x1+b⋅y1=b⋅x2+(a%b)⋅y2
=b⋅x2+(a−b⋅⌊ba⌋)⋅y2=a⋅y2+b⋅(x2−⌊ba⌋⋅y2)
故 x1=y2,y1=(x2−⌊ba⌋⋅y2)
如此递归直至边界情况
- 边界:
当 b=0 时,gcd(a,b)=a(任何数都能整除 0 )
a⋅x+b⋅y=a⋅x=gcd(a,b)⋅x
若使 a\*x + b\*y = gcd(a, b) ,只需 x=1 ,y 可以为任何值,通常设为 0 ,减少溢出的风险
y 的多值对应方程的多解
- 通解:
对于对于第一个解 x0 和 y0 ,其他解可以表示为 x0+db⋅k 和 y0−da⋅k
推导:
令 a⋅(x+m)+b⋅(x−n)=d
⇒a⋅m=b⋅n⇒nm=ab
因 gcd(a,b)=d ,m 和 n 均为整数
故 m 和 n 的最小值分别为 db 和 da
若要求其中一个解为正整数,可在得到负解后用通解转化为正数
- 代码:
1 2 3 4 5 6 7 8 9
| void exgcd(int a,int b,int &x,int &y){ if(!b){ x=1,y=0; return ; } exgcd(b,a%b,x,y); int z=x; x=y,y=(z-a/b*y); }
|
- 易错点:
算法中存在乘法,有溢出的风险,应见机开 long long
例题:
洛谷4549 裴蜀定理
洛谷1516 青蛙的约会
洛谷3951 小凯的疑惑
洛谷1082 同余方程