数论——扩展欧几里得算法
扩展欧几里得算法
定义:
通常谈到最大公因子时, 我们都会提到一个非常基本的事实: 给予二整数 a 与 b, 必存在有整数 x 与 y 使得ax + by = gcd(a,b)。有两个数a,b,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到ax+by=gcd(a,b)的整数解。
应用:
求解线性同余方程,求逆元
算法原理描述
(
1
)
a
x
i
+
b
y
i
=
g
c
d
(
a
,
b
)
(1)ax_i\ +by_i = gcd(a, b)
(1)axi +byi=gcd(a,b)
(
2
)
b
x
i
−
1
+
(
a
%
b
)
y
i
−
1
=
g
c
d
(
b
,
a
%
b
)
(2)bx_{i - 1} + (a \% b) y_{i - 1} = gcd(b, a \% b)
(2)bxi−1+(a%b)yi−1=gcd(b,a%b)
(
3
)
a
%
b
)
x
i
−
2
+
[
b
%
(
a
%
b
)
]
y
i
−
2
=
g
c
d
(
b
,
a
%
b
)
(3)a \% b)x_{i - 2} + [b \%(a \% b) ]y_{i - 2} = gcd(b, a \% b)
(3)a%b)xi−2+[b%(a%b)]yi−2=gcd(b,a%b)
.
.
.
.
.
.
.
.
........
........
(
n
)
d
∗
1
+
0
=
g
c
d
(
a
,
b
)
(n)d* 1 + 0 = gcd(a, b)
(n)d∗1+0=gcd(a,b)
(1)、(2)式,(2)式可以转换成
a
y
i
−
1
+
b
(
x
i
−
1
−
(
a
/
/
b
)
y
i
−
1
)
ay_{i - 1} + b(x_{i - 1} - (a // b)y_{i - 1})
ayi−1+b(xi−1−(a//b)yi−1),可以求得
x
i
=
y
i
−
1
x_i = y_{i - 1}
xi=yi−1,
y
i
=
x
i
−
1
−
(
a
/
/
b
)
y
i
−
1
y_{i} = x_{i - 1} - (a // b)y_{i - 1}
yi=xi−1−(a//b)yi−1
同理(2)式转换为(1)式形式,相对于(3)式的关系也是一样的,可以通过递归实现
例题
模板题
给定 n 对正整数 ai,bi,对于每对数,求出一组 xi,yi,使其满足 ai×xi+bi×yi=gcd(ai,bi)。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 ai,bi。
输出格式
输出共 n 行,对于每组 ai,bi,求出一组满足条件的 xi,yi,每组结果占一行。
本题答案不唯一,输出任意满足条件的 xi,yi 均可。
数据范围
1≤n≤10^5,
1≤ai,bi≤2×10^9
输入样例:
2
4 6
8 18
输出样例:
-1 1
-2 1
n = int(input())
def exgcd(a, b) :
if b == 0 :
return 1, 0, a
x, y, d = exgcd(b, a % b)
x, y = y, x - (a // b) * y
return x, y, d
for i in range(n) :
a, b = map(int, input().split())
res = exgcd(a, b)
print(res[0], res[1], end = " ")
print()
求线性同余方程
给定 n 组数据 ai,bi,mi,对于每组数求出一个 xi,使其满足 a i × x i ≡ b i ( m o d m i ) a_i×x_i≡b_i(mod \ m_i) ai×xi≡bi(mod mi),如果无解则输出 impossible。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一组数据 ai,bi,mi。
输出格式
输出共 n 行,每组数据输出一个整数表示一个满足条件的 xi,如果无解则输出 impossible。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 int 范围之内。
数据范围
1≤n≤10^5,
1≤ai,bi,mi≤2×10^9
输入样例:
2
2 3 6
4 3 5
输出样例:
impossible
-3
思路讲解
a × x ≡ b ( m o d m ) a×x≡b(mod \ m) a×x≡b(mod m)=> a x + m y = b ax + my = b ax+my=b,则 g c d ( a , m ) ∣ b gcd(a,m) | b gcd(a,m)∣b,通过扩展欧几里得算法 a x ′ + m y ′ = g c d ( a , m ) ax^{'} + my^{'} = gcd(a, m) ax′+my′=gcd(a,m)可以求得 a ∗ x ′ ≡ g c d ( a , m ) ( m o d m ) a * x^{'}≡gcd(a, m) (mod \ m) a∗x′≡gcd(a,m)(mod m),中的x’由模的乘法运算知, a ∗ x ′ ∗ ( b / / g c d ( a , m ) ) m o d m ≡ b ( m o d m ) a * x^{'} * (b // gcd(a, m)) mod \ m≡b (mod \ m) a∗x′∗(b//gcd(a,m))mod m≡b(mod m)
n = int(input())
def exgcd(a, b) :
if b == 0 :
return 1, 0, a
x, y, d = exgcd(b, a % b)
return y, x - (a // b) * y, d
for i in range(n) :
a, b, m = map(int, input().split())
res = exgcd(a, m)
if b % res[2] != 0 :
print("impossible")
else :
print(res[0] * (b // res[2]) % m)
总结
这篇关于欧几里得算法的讲解算是非常详细了,此外欧几里得算法对于求解逆元是非常有帮助的,相当于线性同余方程 a × x ≡ b ( m o d m ) a×x≡b(mod \ m) a×x≡b(mod m),中b = 1的情况
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!