扩展欧几里德数学分析
此文献给那些对于算法背后的数学知识真正热爱的人,一贯的只谈数学部分的内容,共勉
写这类文章的目的是为了使数学不在那么吓人,网上搜索资料时,有适合我这种对数学不太敏感的人能看懂的博客,所以内容在确保正确性的前提下尽量保证简单易懂
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1; y = 0; return a;
}
int ans = exgcd(b, a%b, y, x);
y -= a / b * x;
return ans;
}
本文不会过多涉及到代码,只对一些操作说明数学上的正确性
数学分析
引理:存在 x , y 使得 g c d ( a , b ) = a × x + b × y gcd(a,b) = a\times x+b\times y gcd(a,b)=a×x+b×y
证明:
- 当
b
=
0
b=0
b=0 时,
a × x + b × y = g c d ( a , b ) = a a\times x + b\times y = gcd(a,b) = a a×x+b×y=gcd(a,b)=a
易得
{ x = 1 y = 0 \begin{cases} x=1\\ y=0 \end{cases} {x=1y=0 - 当
b
≠
0
b\neq0
b̸=0 时,
a × x 1 + b × y 1 = g c d ( a , b ) a\times x_1+b\times y_1 = gcd(a,b) a×x1+b×y1=gcd(a,b)
b × x 2 + ( a % b ) × y 2 = g c d ( b , a % b ) b\times x_2+(a\%b)\times y_2 = gcd(b,a\%b) b×x2+(a%b)×y2=gcd(b,a%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)
由上式得出
a × x 1 + b × y 1 = b × x 2 + ( a % b ) × y 2 a\times x_1+b\times y_1 = b\times x_2+(a\%b)\times y_2 a×x1+b×y1=b×x2+(a%b)×y2
因
a % b = a − ⌊ a b ⌋ × b a\%b = a-\lfloor\frac{a}{b}\rfloor\times b a%b=a−⌊ba⌋×b
则带入式子可得
a × x 1 + b × y 1 = b × x 2 + ( a − ⌊ a b ⌋ × b ) × y 2 a\times x_1+b\times y_1 = b\times x_2+(a-\lfloor\frac{a}{b}\rfloor\times b)\times y_2 a×x1+b×y1=b×x2+(a−⌊ba⌋×b)×y2
进一步整理
a × x 1 + b × y 1 = a × y 2 + b × ( x 2 − ⌊ a b ⌋ × y 2 ) a\times x_1+b\times y_1 = a\times y_2+b\times(x_2-\lfloor\frac{a}{b}\rfloor\times y_2) a×x1+b×y1=a×y2+b×(x2−⌊ba⌋×y2)
可以解得
{ x 1 = y 2 y 1 = x 2 − ⌊ a b ⌋ × y 2 \begin{cases} x_1=y_2\\ y_1=x_2-\lfloor\frac{a}{b}\rfloor\times y_2 \end{cases} {x1=y2y1=x2−⌊ba⌋×y2
上式即为代码中int ans = exgcd(b, a%b, y, x);
和y -= a / b * x;
关键所在。
所以在能得出方程解的情况下缩小了第二项的系数,即该试的第二项系数成功缩小
a × x 1 + b × y 1 = b × x 2 + ( a % b ) × y 2 a\times x_1+b\times y_1 = b\times x_2+(a\%b)\times y_2 a×x1+b×y1=b×x2+(a%b)×y2
递归进行下去,第二项系数会变成 0 ,此时就回到了第一种情况,然后递归地返回答案
应用
解不定方程
经过上面的分析,可以十分确定地知道扩展欧几里德可以解决
a
×
x
+
b
×
y
=
g
c
d
(
a
,
b
)
a\times x+b\times y=gcd(a,b)
a×x+b×y=gcd(a,b)
略微推广一下,同样可以解决下面这样的式子
a
×
x
+
b
×
y
=
d
g
c
d
(
a
,
b
)
∣
d
a\times x+b\times y=d_{gcd(a,b)|d}
a×x+b×y=dgcd(a,b)∣d
注意,解得的 x 和 y 可能为负数,可以对求出来的 x 和 y 进行变形
{
x
0
=
x
+
k
×
b
y
0
=
y
−
k
×
a
\begin{cases} x_0=x+k\times b\\ y_0=y-k\times a \end{cases}
{x0=x+k×by0=y−k×a
变形的正确性如下,如果一对解 x 和 y 符合原式
a
×
x
+
b
×
y
=
d
a\times x+b\times y=d
a×x+b×y=d
则对 x 加上 k 倍的 b,对 y 减去 k 倍的 a ,代入
求乘法逆元
a
×
x
≡
1
(
m
o
d
p
)
a\times x \equiv 1(mod\ p)
a×x≡1(mod p)
那么我们就称 x 为 a 模 p 意义下的乘法逆元,上式可变形为
a
×
x
=
1
+
p
×
(
−
y
)
a\times x = 1+p\times (-y)
a×x=1+p×(−y)
即
a
×
x
+
p
×
y
=
1
a\times x + p\times y = 1
a×x+p×y=1
因为原式可得, a 与 p 互质,即
g
c
d
(
a
,
p
)
=
1
gcd(a,p)=1
gcd(a,p)=1
所以带入扩展欧几里德变为解不定方程问题
解一元线性同余方程
求该方程的解
a
×
x
≡
c
(
m
o
d
b
)
a\times x\equiv c(mod\ b)
a×x≡c(mod b)
方程可转换为
a
×
x
+
b
×
y
=
c
a\times x+b\times y=c
a×x+b×y=c
当前仅当下式成立时有解, k 为正整数
c
=
k
×
g
c
d
(
a
,
b
)
c = k\times gcd(a,b)
c=k×gcd(a,b)
令
r
=
c
g
c
d
(
a
,
b
)
r=\frac{c}{gcd(a,b)}
r=gcd(a,b)c ,使得第二个式子两端同时除以
r
r
r
a
×
x
d
+
b
×
y
d
=
g
c
d
(
a
,
b
)
\frac{a\times x}{d}+\frac{b\times y}{d} = gcd(a,b)
da×x+db×y=gcd(a,b)
代入扩展欧几里德时相当于求的该式
a
×
x
d
+
b
×
y
d
=
g
c
d
(
a
,
b
)
a\times\frac{x}{d}+b\times\frac{y}{d} = gcd(a,b)
a×dx+b×dy=gcd(a,b)
求得对应的
x
0
x_0
x0 和
y
0
y_0
y0 需要乘以
r
r
r
总结
在 解决求乘法逆元 和 解一元线性同余方程 问题时都转化为了 解不定方程 ,如果对结果的正符号有要求的,都可以通过 解不定方程 里讲到的变形来处理。