欧几里得算法和扩展欧几里得算法——杨子曰数学
超链接:数学合集
不说废话,咱们直接开始
欧几里得算法
一句话:
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,a mod b)
简单证明:
首先我们先来证一证这个: g c d ( a , b ) = g c d ( b , a − b ) gcd(a,b)=gcd(b,a-b) gcd(a,b)=gcd(b,a−b)
假设: d = g c d ( a , b ) , a = k a ∗ d , b = k b ∗ d ( k a 和 k b 互 质 ) d=gcd(a,b),a=k_a*d,b=k_b*d(k_a和k_b互质) d=gcd(a,b),a=ka∗d,b=kb∗d(ka和kb互质)
这样一来,我们会发现:
a
−
b
=
k
a
∗
d
−
k
b
∗
d
=
(
k
a
−
k
b
)
∗
d
a-b=k_a*d-k_b*d=(k_a-k_b)*d
a−b=ka∗d−kb∗d=(ka−kb)∗d
欧,有没有发现a-b和b还是都有公因子d
a − b = ( k a − k b ) ∗ d a-b=(k_a-k_b)*d a−b=(ka−kb)∗d
b = k b ∗ d b=k_b*d b=kb∗d
BUT,我们还要证明d是它们的最大公因子,也就是要证明,它们的系数 k a − k b k_a-k_b ka−kb和 k b k_b kb的互质(它们如果不互质,那么最大公因数就会变成 d ∗ g c d ( k a − k b , k b ) d*gcd(k_a-k_b,k_b) d∗gcd(ka−kb,kb))
我们用反证法:
假设 k a − k b k_a-k_b ka−kb和 k b k_b kb不互质
设
:
g
c
d
(
k
a
−
k
b
,
k
b
)
=
λ
(
λ
>
1
)
,
k
a
−
k
b
=
α
∗
λ
,
k
b
=
β
∗
λ
设:gcd(k_a-k_b,k_b)=\lambda(\lambda>1),k_a-k_b=\alpha*\lambda,k_b=\beta*\lambda
设:gcd(ka−kb,kb)=λ(λ>1),ka−kb=α∗λ,kb=β∗λ
于是
k
a
=
k
a
−
k
b
+
k
b
=
α
∗
λ
+
β
∗
λ
=
(
α
+
β
)
∗
λ
k_a=k_a-k_b+k_b=\alpha*\lambda+\beta*\lambda=(\alpha+\beta)*\lambda
ka=ka−kb+kb=α∗λ+β∗λ=(α+β)∗λ
有没有发现 k a k_a ka和 k b k_b kb有了公因数 λ \lambda λ,别忘了上面还有一个条件叫 k a 和 k b 互 质 k_a和k_b互质 ka和kb互质
于是得证!
然后我们就得到了: g c d ( a , b ) = g c d ( b , a − b ) gcd(a,b)=gcd(b,a-b) gcd(a,b)=gcd(b,a−b)
然后,我们把a-b看成等式左边新的b,然后一直拿a减,直到不能减了为止,其实就是:
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,a mod b)
得证!
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
扩展欧几里得算法
这个东西只有一个作用
求
a
x
+
b
y
=
g
c
d
(
a
,
b
)
的
整
数
解
求ax+by=gcd(a,b)的整数解
求ax+by=gcd(a,b)的整数解
假设存在一组x’和y’使得:
b
x
′
+
(
a
m
o
d
b
)
y
′
=
g
c
d
(
b
,
a
m
o
d
b
)
bx'+(a\ mod\ b)y'=gcd(b,a\ mod\ b)
bx′+(a mod b)y′=gcd(b,a 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,a mod b)
我们就得到了:
a
x
+
b
y
=
b
x
′
+
(
a
m
o
d
b
)
y
′
ax+by=bx'+(a\ mod\ b)y'
ax+by=bx′+(a mod b)y′
幼儿园小盆友都知道:
a
m
o
d
b
=
a
−
⌊
a
b
⌋
∗
b
a\ mod\ b=a-\lfloor\frac{a}{b}\rfloor*b
a mod b=a−⌊ba⌋∗b
然后把它带回去:
a
x
+
b
y
=
b
x
′
+
(
a
−
⌊
a
b
⌋
∗
b
)
y
′
ax+by=bx'+(a-\lfloor\frac{a}{b}\rfloor*b)y'
ax+by=bx′+(a−⌊ba⌋∗b)y′
把括号拆开:
a
x
+
b
y
=
b
x
′
+
a
y
′
−
⌊
a
b
⌋
∗
b
y
′
ax+by=bx'+ay'-\lfloor\frac{a}{b}\rfloor*by'
ax+by=bx′+ay′−⌊ba⌋∗by′
再合并一下:
a
x
+
b
y
=
a
y
′
+
b
(
x
′
−
⌊
a
b
⌋
∗
y
′
)
ax+by=ay'+b(x'-\lfloor\frac{a}{b}\rfloor*y')
ax+by=ay′+b(x′−⌊ba⌋∗y′)
So,你有没有惊奇的发现一定有一组解长这样:
{
x
=
y
′
y
=
x
′
−
⌊
a
b
⌋
∗
y
′
\left\{ \begin{aligned} x&=y'\\ y&=x'-\lfloor\frac{a}{b}\rfloor*y' \end{aligned} \right.
⎩⎨⎧xy=y′=x′−⌊ba⌋∗y′
也就是说我们只要求出x’和y’就可以求出x和y了
我们再来回头看一下它们的方程:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)
b
x
′
+
(
a
m
o
d
b
)
y
′
=
g
c
d
(
b
,
a
m
o
d
b
)
bx'+(a\ mod\ b)y'=gcd(b,a\ mod\ b)
bx′+(a mod b)y′=gcd(b,a mod b)
有没有发现形式是一样滴,So,我们可以通过递归来解决它
那么临界情况是什么捏?
一个幼儿园小盆友都知道的事实:
g
c
d
(
a
,
0
)
=
a
gcd(a,0)=a
gcd(a,0)=a
So,当b=0时:
a
x
+
0
=
g
c
d
(
a
,
0
)
ax+0=gcd(a,0)
ax+0=gcd(a,0)
然后就可以,美滋滋地让x=1,y是任意值了(一般是0,它会影响最后的解的大小)
OK,完事
void ex_gcd(int a,int b,int &x,int &y){
if(!b) x=1,y=0;
else ex_gcd(b,a%b,y,x),y-=(a/b)*x;
}
应用1:解方程ax+by=c
首先,在上面已经讲过了,扩展欧几里得可以求长这样的方程:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)
那有什么卵用!我从来没有在哪道题里见长成这样的方程
BUT,我们可以利用它来解长成这样的方程:
a
x
+
b
y
=
c
ax+by=c
ax+by=c
让
d
=
g
c
d
(
a
,
b
)
d=gcd(a,b)
d=gcd(a,b)
这时,如果我们把这个方程同时乘上一个
d
c
\frac{d}{c}
cd
方程就变成了:
a
d
c
∗
x
+
b
d
c
∗
y
=
g
c
d
(
a
,
b
)
a\frac{d}{c}*x+b\frac{d}{c}*y=gcd(a,b)
acd∗x+bcd∗y=gcd(a,b)
我们就可以来解一个这样的方程:
a x ′ + b y ′ = g c d ( a , b ) ax'+by'=gcd(a,b) ax′+by′=gcd(a,b)
于是你就会发现,原方程的解就是:
{
x
=
x
′
∗
c
d
y
=
x
′
∗
c
d
\left\{ \begin{aligned} x&=x'*\frac{c}{d}\\ y&=x'*\frac{c}{d} \end{aligned} \right.
⎩⎪⎨⎪⎧xy=x′∗dc=x′∗dc
你一定会问了c如果不是d的倍数肿么办?
那就没有整数解呗!这有什么好问的?
应用2:解模线性方程: a x ≡ b ( m o d p ) ax\equiv b(mod\ p) ax≡b(mod p)
其实就是应用1,有没有发现
a
x
≡
b
(
m
o
d
p
)
ax\equiv b(mod\ p)
ax≡b(mod p),就是:
a
x
+
p
y
=
b
ax+py=b
ax+py=b,然后再用上面的那个东东解出来就好了
解模线性方程,就可以做很多事情了,比如:求逆元,戳我
参考:
https://www.zybuluo.com/samzhang/note/541890
于HG机房