拓展欧几里得学习笔记
# 前言
今天队友在群上问了一题,链接 (opens new window),正解是拓展欧几里得,然而我的第一想法是同余最短路(因为我连拓展欧几里得都不会...)~
PS. 同余最短路的复杂度,拓展欧几里得复杂度
# 拓展欧几里得
求的一组解
# 定理1: 有整数解,则定有
下面用来代替
可知且,因此,有
# 定理2: 若,则有整数解
事实上,这一定理可以用拓展欧几里得的过程来证明,但这里尝试用另一种方法证明。
设的最小正整数结果为,现在证明
由于为的线性组合,且,因此,即
因而有
因此也是的线性组合,又因为为最小正整数,因此,
同理,可知为的公因数,又知为的最大公因数,因此,即
综上,
上述两条定理合在一起称为裴蜀定理
# 拓展欧几里得
这样一来,问题转化为求的一组解
代码只有四行
C++版
ll exgcd(ll a, ll b, ll & x, ll & y){
if(b == 0) return x=1, y=0, a;
ll g = exgcd(b, a%b, y, x);
y -= a/b*x;
return g;
}
1
2
3
4
5
6
2
3
4
5
6
Python版
def exgcd(a: int, b: int):
if b == 0: return 1, 0, a
y, x, g = exgcd(b, a % b)
y -= a//b*x
return x, y, g
1
2
3
4
5
2
3
4
5
下面来证明一下。
根据定理2,我们有
因而
考虑展开求余符号'',得到
稍微化简得:
显然有一组解
设,显然有,因而经过上述步骤之后,问题转化为了一个规模"更小"的子问题,可以递归求解。
考虑递归求解的边界,回想一下欧几里得算法的边界,定有,即,此时的。因而为一组可行解。我们把这组解回代,求出,最终求得
现在得到,要求,显然有,
# 常用式子
已知一组解,其通解为
# 求最小正整数解
假设我们对找到一组解,那么对于,求最小正整数解
令
有,设,因此
考虑让新解,为了使等式平衡,需要使
即:,因而
注意这里不应当约掉,因为越小,越能得到小的整数解
因而有
# 洛谷P1516
def exgcd(a: int, b: int):
if b == 0: return 1, 0, a
y, x, g = exgcd(b, a%b)
y -= a//b*x
return x, y, g
x, y, m, n, L = map(int, input().split())
t, _, g = exgcd(n - m, L)
if (x - y) % g is not 0:
print('Impossible')
else:
t = t * ((x - y) // g)
t = (t % (L // g) + (L // g)) % (L // g)
print(t)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 模板
Python:
def exgcd(a: int, b: int):
if b == 0: return 1, 0, a
y, x, g = exgcd(b, a % b)
y -= a//b*x
return x, y, g
def solve_linear(a, b, ans):
"""
解ax+by=ans,且x为最小非负数
"""
x, y, g = exgcd(a, b)
factor = ans // g
x, y = x * factor, y * factor
m1, m2 = b // g, a // g
delta = x // m1 # 向下取整, 而不是截尾
x, y = x - delta * m1, y + delta * m2
return x, y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C++:
自己把上面的代码翻译一下就好。。
上次更新: 2021/02/24, 03:37:30