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