拓展欧几里得算法,可以用来求解一个一元二次方程的特解。
形如:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax + by =gcd(a,b)
ax+by=gcd(a,b)及其变式
为什么是拓展欧几里得呢,因为这个特解是从欧几里得算法(辗转相除法)的基础上来求得的,即
g
c
d
−
>
e
x
g
c
d
gcd -> exgcd
gcd−>exgcd。
我们知道求
g
c
d
gcd
gcd时,最后
r
e
t
u
r
n
return
return出来的结果是
b
b
b,如果我们此时再往深递归一层,也就是
b
=
0
b = 0
b=0的时候,此时返回的结果值就是
g
c
d
=
a
gcd = a
gcd=a,由此我们得到了在此情况下的一个特殊解
x
=
1
,
y
=
0
x = 1,y = 0
x=1,y=0,由这个解我们就可以回溯一层层的求出其它的解了。
由
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),我们设当前层为
g
c
d
(
b
,
a
%
b
)
gcd(b,a\%b)
gcd(b,a%b)的话,设特解为
x
0
和
y
0
x_0 和 y_0
x0和y0,其上一层的解为
x
1
和
y
1
x_1和y_1
x1和y1,那么
a
x
1
+
b
y
1
=
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
=
b
x
0
+
(
a
%
b
)
y
0
ax_1 + by_1 = gcd(a,b) = gcd(b,a\%b) = bx_0 + (a\%b)y_0
ax1+by1=gcd(a,b)=gcd(b,a%b)=bx0+(a%b)y0,由可知
a
%
b
=
a
−
a
b
∗
b
a\%b = a - \frac ab * b
a%b=a−ba∗b,则
a
x
1
+
b
y
1
=
b
x
0
+
(
a
%
b
)
y
0
=
b
x
0
+
(
a
−
a
b
∗
b
)
y
0
=
a
y
0
+
b
(
x
0
−
a
b
y
0
)
ax_1 +by_1 = bx_0 + (a\%b)y_0 = bx_0 + (a - \frac ab*b)y_0 = ay_0 + b(x_0 - \frac aby_0)
ax1+by1=bx0+(a%b)y0=bx0+(a−ba∗b)y0=ay0+b(x0−bay0)
这样通过对应系数相等,我们就可以比较出来
{
x
1
=
y
0
y
1
=
x
0
−
a
b
∗
b
\begin{cases} x_1 = y_0 \\ y_1 = x_0 - \frac ab*b\end{cases}
{x1=y0y1=x0−ba∗b
这样我们就可以得到回溯得到我们需要的一组解了。
一
如果题目要我们求得是
a
x
+
b
y
=
c
ax + by = c
ax+by=c这样的不定方程的解,如果
c
%
g
c
d
(
a
,
b
)
≠
0
c \% gcd(a,b) \neq 0
c%gcd(a,b)=0,那么就无解,否则的话只需要把
c
c
c先除到等式左边再乘上
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)就变成了一般我们熟悉的形式了。
同理这样的我们求出来的
x
和
y
x和y
x和y,也应改逆向操作,先除
g
c
d
gcd
gcd再乘
c
c
c,就是我们要求的解了。
二
如果求
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax + by = gcd(a,b)
ax+by=gcd(a,b)的多组解,我们可以构造
x
=
x
∗
+
k
∗
b
x = x^* + k * b
x=x∗+k∗b,
y
=
y
∗
−
k
∗
a
y = y^* - k * a
y=y∗−k∗a,形如这样的解带回原方程还是只剩下
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax + by = gcd(a,b)
ax+by=gcd(a,b)这样的形式,注意这里有个细节就是防止
a
a
a和
b
b
b不互质这里要用
a
g
c
d
(
a
,
b
)
\frac a{gcd(a,b)}
gcd(a,b)a和
b
g
c
d
(
a
,
b
)
\frac b{gcd(a,b)}
gcd(a,b)b操作。
三
如果求得是最小的正整数解,求出来的
x
x
x只需要先令
t
=
b
g
c
d
(
a
,
b
)
t = \frac b{gcd(a,b)}
t=gcd(a,b)b(保证其为正,后面要取模),然后
x
=
(
x
%
t
+
t
)
%
t
x = (x \%t + t)\%t
x=(x%t+t)%t即可。
证明的话,这篇大佬博客写的不错
四
还可以用扩展欧几里得算法来求解逆元,
a
x
≡
1
(
m
o
d
p
)
ax \equiv 1 (modp)
ax≡1(modp),即说明我们知道逆元存在条件即为
g
c
d
(
a
,
p
)
=
1
gcd(a,p) = 1
gcd(a,p)=1,这样同余式其实就是可化为
a
x
+
p
y
=
1
ax + py = 1
ax+py=1,这样逆元就可以用拓欧来直接求出来了。
未完待续~
void exgcd(int a,int b,int &x,int &y) {//拓欧求逆元
if(b == 0) {//最后一层 满足 ax + by = gcd(a,b) 的特解 x = 1,y = 0
x = 1; y = 0;
return ;
}
exgcd(b,a%b,x,y);//上一层的特解x
int t = x; //x = y1,y = x1 - (a/b)*y1
x = y;
y = t - a / b * y;
}