注意:本篇文章会涉及到较多的数论的符号,如果有些符号您不认识,可以跳转到数论之基础一文查看某符号的定义
⋅ 欧几里得算法 ·欧几里得算法 ⋅欧几里得算法
1 、 g c d ( a , b ) = g c d ( b , a % b ) 1、gcd(a, b) = gcd(b, a\%b) 1、gcd(a,b)=gcd(b,a%b)
即 ( a , b ) (a, b) (a,b) 与 ( b , a % b ) (b, a\%b) (b,a%b)的最大公约数相同,这是辗转相除法的基本原理;
2 、 l c m ( a , b ) = a × b g c d ( a , b ) 2、lcm(a, b) = \dfrac {a \times b}{gcd(a,b)} 2、lcm(a,b)=gcd(a,b)a×b
l c m lcm lcm是最大公倍数
为了避免 a × b a \times b a×b 爆 l o n g l o n g long\quad long longlong,最好写成 a / g c d ( a , b ) ∗ b a/ gcd(a,b) * b a/gcd(a,b)∗b的形式;
3 、 3、 3、辗转相除法的代码实现:
int gcd(int a, int b)
{
return b==0 ? a : gcd(b, a%b);
}
⋅ 拓展欧几里得算法 ·拓展欧几里得算法 ⋅拓展欧几里得算法
前置知识:裴蜀定理
1 、 1、 1、一般用于求解 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的解。
当 b = 0 b=0 b=0时, a x + b y = a ax+by=a ax+by=a,故而 x = 1 , y = 0 x=1, y=0 x=1,y=0.
当
b
≠
0
b\neq0
b=0时:
∵
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
则
:
b
x
′
+
(
a
%
b
)
×
y
′
=
g
c
d
(
b
,
a
%
b
)
b
x
′
+
(
a
−
⌊
a
/
b
⌋
)
×
y
′
=
g
c
d
(
b
,
a
%
b
)
a
y
′
+
b
×
(
x
′
−
⌊
a
/
b
⌋
×
y
′
)
=
g
c
d
(
b
,
a
%
b
)
∴
x
=
y
′
,
y
=
x
′
−
⌊
a
/
b
⌋
∗
y
′
\begin{aligned} \because gcd(a,b)=gcd(b, a\%b) \\ 则:bx^{'} + (a\%b) \times y^{'} = gcd(b, a\%b) \\ bx^{'} + (a-\lfloor a/b \rfloor) \times y^{'}=gcd(b, a\%b) \\ ay^{'}+b \times (x^{'}-\lfloor a/b \rfloor \times y^{'})=gcd(b, a\%b) \\ \therefore x = y^{'}, \quad y = x^{'}-\lfloor a/b \rfloor * y^{'} \end{aligned}
∵gcd(a,b)=gcd(b,a%b)则:bx′+(a%b)×y′=gcd(b,a%b)bx′+(a−⌊a/b⌋)×y′=gcd(b,a%b)ay′+b×(x′−⌊a/b⌋×y′)=gcd(b,a%b)∴x=y′,y=x′−⌊a/b⌋∗y′
则有C++代码实现如下:
int exgcd(int a, int b, int &x, int &y)
{
if(b == 0) {
x = 1, y = 0;
return a;
}
int x1, y1, gcd;
gcd = exgcd(b, a%b, x1, y1);
x = y1, y = x1 - a/b*y1; //C++中的两个整数相除自动会下取整
return gcd;
}
另一种证明方法及代码实现:
当 b = 0 b=0 b=0时, a x + b y = a ax+by=a ax+by=a,故而 x = 1 , y = 0 x=1, y=0 x=1,y=0.
当
b
≠
0
b\neq0
b=0时:
∵
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
=
g
c
d
(
a
%
b
,
b
)
b
y
′
+
a
%
b
×
x
′
=
g
c
d
(
a
%
b
,
b
)
b
y
′
+
x
′
(
a
−
⌊
a
/
b
⌋
×
b
)
=
g
c
d
(
a
%
b
,
b
)
a
x
′
+
b
(
y
′
−
⌊
a
/
b
⌋
×
x
′
)
=
g
c
d
(
a
%
b
,
b
)
∴
x
=
x
′
,
y
=
y
′
−
⌊
a
/
b
⌋
×
x
′
\begin{aligned} \because gcd(a, b) = gcd(b, a\%b) = gcd(a\%b, b) \\ by^{'} + a\%b \times x^{'} = gcd(a\%b, b) \\ by^{'} + x^{'}(a - \lfloor a/b \rfloor \times b) = gcd(a\%b, b) \\ ax^{'} + b(y^{'} - \lfloor a/b \rfloor \times x^{'}) = gcd(a\%b, b) \\ \therefore x = x^{'}, \quad y = y^{'} - \lfloor a/b \rfloor \times x^{'} \end{aligned}
∵gcd(a,b)=gcd(b,a%b)=gcd(a%b,b)by′+a%b×x′=gcd(a%b,b)by′+x′(a−⌊a/b⌋×b)=gcd(a%b,b)ax′+b(y′−⌊a/b⌋×x′)=gcd(a%b,b)∴x=x′,y=y′−⌊a/b⌋×x′
则有C++代码实现如下:
int exgcd(int a, int b, int &x, int &y)
{
if(b == 0) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a%b, y, x);
y -= a/b*x;
return d;
}
我个人喜好第二种证明方式,因为比较好理解,代码也相对而言比较容易实现。
2 、 2、 2、对于求解更一般的方程 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 . d|c. d∣c.
求解方法:
用拓展欧几里得求出 a x 0 + b y 0 = d ax_0 + by_0 = d ax0+by0=d的解.
则 a ( x 0 ∗ c / d ) + b ( y 0 ∗ c / d ) = c a(x_0 * c/d) + b(y_0 * c/d) = c a(x0∗c/d)+b(y0∗c/d)=c
故特解为 x ′ = x 0 ∗ c / d , y ′ = y 0 ∗ c / d x^{'} = x_0 * c/d, \quad y^{'} = y_0 * c/d x′=x0∗c/d,y′=y0∗c/d.
而 通解 = 特解 + 齐次解 通解 = 特解 + 齐次解 通解=特解+齐次解,齐次解即为 a x + b y = 0 ax + by = 0 ax+by=0的解
故而通解为 x = x ′ + k ∗ b / d , y = y ′ − k ∗ a / d , k ∈ z x = x^{'} + k * b/d, \quad y = y^{'} - k * a/d, \quad k \in z x=x′+k∗b/d,y=y′−k∗a/d,k∈z
若令 t = b / d , t = b/d, \quad t=b/d,则对于 x x x的最小非负整数解为 ( x ′ % t + t ) % t (x^{'}\%t + t) \% t (x′%t+t)%t
然后将 x x x代入原式,即可得到 y y y的解.
3 、 3、 3、应用:求解一次同余方程 a x ≡ b ( m o d m ) ax \equiv b(\bmod m) ax≡b(modm)
则等价于求:
a
x
=
m
×
(
−
y
)
+
b
a
x
+
m
y
=
b
ax = m \times (-y) + b \\ ax + my = b
ax=m×(−y)+bax+my=b
有解的条件为
g
c
d
(
a
,
m
)
∣
b
gcd(a, m)|b
gcd(a,m)∣b,然后用拓展欧几里得求解即可.
特别的,当 b = 1 b = 1 b=1且 a a a与 m m m互质时,则所求 x x x即为 a a a的逆元.
原创文章,如需转载,请标明出处。