Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 数论

    • 一些小问题
    • 二次剩余学习笔记
    • 卡特兰数学习笔记
    • 同余最短路学习笔记
    • 康托展开学习笔记
    • 快速傅里叶变换学习笔记
    • 拉格朗日插值学习笔记
    • 拓展欧几里得学习笔记
      • 定理1: $ax+by=m$有整数解,则定有$gcd(a,b)\mid m$
      • 定理2: 若$gcd(a,b) \mid m$,则$ax+by=m$有整数解
      • 拓展欧几里得
      • 常用式子
      • 求最小正整数解
        • 模板
    • 斐波那契数列学习笔记
    • 斯特林数笔记
    • 本原勾股数组学习笔记
    • 模运算学习笔记
    • 欧拉函数
    • 类欧几里得学习笔记
    • 素性检测与大数分解
    • 素数计数问题
    • 组合数问题
    • 高斯整数学习笔记
  • 动态规划

  • 暴力

  • 图论

  • 数据结构

  • 字符串

  • 几何

  • 博弈论

  • 其他

拓展欧几里得学习笔记

# 前言

今天队友在群上问了一题,链接 (opens new window),正解是拓展欧几里得,然而我的第一想法是同余最短路(因为我连拓展欧几里得都不会...)~

PS. 同余最短路的复杂度O(nlogn),n=1e5O(nlogn),\ n=1e5O(nlogn),n=1e5,拓展欧几里得复杂度O(1)O(1)O(1)

# 拓展欧几里得

求ax+by=max+by=max+by=m的一组解(x,y)(x,y)(x,y)

# 定理1: ax+by=max+by=max+by=m有整数解,则定有gcd(a,b)∣mgcd(a,b)\mid mgcd(a,b)∣m

下面用ggg来代替gcd(a,b)gcd(a,b)gcd(a,b)

可知g∣ag\mid ag∣a且g∣bg\mid bg∣b,因此,有g∣(ax+by)g \mid(ax+by)g∣(ax+by)

# 定理2: 若gcd(a,b)∣mgcd(a,b) \mid mgcd(a,b)∣m,则ax+by=max+by=max+by=m有整数解

事实上,这一定理可以用拓展欧几里得的过程来证明,但这里尝试用另一种方法证明。


设ax+byax+byax+by的最小正整数结果为sss,现在证明s=gs=gs=g

由于sss为a,ba,ba,b的线性组合,且g∣a,g∣bg\mid a, g\mid bg∣a,g∣b,因此g∣sg\mid sg∣s,即g≤sg\le sg≤s

令q=⌊as⌋,p=amods\text{令} q=\lfloor \frac{a}{s} \rfloor, p=a\mod s 令q=⌊sa​⌋,p=amods

因而有

p=a−qs=a−q(ax0+by0)=a(1−qx0)−b(qy0)\begin{aligned}p & = a-qs\\ & = a-q(ax_0+by_0)\\ & = a(1-qx_0)-b(qy_0)\end{aligned} p​=a−qs=a−q(ax0​+by0​)=a(1−qx0​)−b(qy0​)​

因此ppp也是a,ba,ba,b的线性组合,又因为sss为最小正整数,因此p=0p=0p=0,s∣as\mid as∣a

同理,可知sss为a,ba,ba,b的公因数,又知ggg为a,ba,ba,b的最大公因数,因此s∣gs\mid gs∣g,即s≤gs\le gs≤g

综上,s=gs=gs=g

上述两条定理合在一起称为裴蜀定理

# 拓展欧几里得

这样一来,问题转化为求ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)的一组解(x,y)(x,y)(x,y)

代码只有四行

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

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

下面来证明一下。


ax0+by0=gcd(a,b)=gcd(b,a%b)ax_0+by_0=gcd(a,b)=gcd(b,a\%b)ax0​+by0​=gcd(a,b)=gcd(b,a%b)

根据定理2,我们有gcd(b,a%b)=bx1+(a%b)y1gcd(b, a\%b)=bx_1+(a\%b)y_1gcd(b,a%b)=bx1​+(a%b)y1​

因而ax0+by0=bx1+(a%b)y1ax_0+by_0=bx_1+(a\%b)y_1ax0​+by0​=bx1​+(a%b)y1​

考虑展开求余符号'%\%%',得到ax0+by0=bx1+(a−⌊ab⌋b)y1ax_0+by_0=bx_1+(a -\lfloor \frac{a}{b} \rfloor b)y_1ax0​+by0​=bx1​+(a−⌊ba​⌋b)y1​

稍微化简得:ax0+by0=ay1+b(x1−⌊ab⌋y1)ax_0+by_0=ay_1+b(x_1-\lfloor \frac{a}{b} \rfloor y_1)ax0​+by0​=ay1​+b(x1​−⌊ba​⌋y1​)

显然x0,y0x_0,y_0x0​,y0​有一组解x0=y1,y0=x1−⌊ab⌋y1x_0=y_1,y_0=x_1-\lfloor \frac{a}{b} \rfloor y_1x0​=y1​,y0​=x1​−⌊ba​⌋y1​


设a′=b,b′=a%ba'=b,b'=a\%ba′=b,b′=a%b,显然有max(a,b)≥max(a′,b′)max(a,b)\ge max(a', b')max(a,b)≥max(a′,b′),因而经过上述步骤之后,问题转化为了一个规模"更小"的子问题,可以递归求解。

考虑递归求解的边界,回想一下欧几里得算法的边界,定有b=0b=0b=0,即axn+0yn=gax_n+0y_n=gaxn​+0yn​=g,此时的g=ag=ag=a。因而xn=1,yn=0x_n=1,y_n=0xn​=1,yn​=0为一组可行解。我们把这组解回代,求出(xn−1,yn−1),(xn−2,yn−2)...(x_{n-1},y_{n-1}), (x_{n-2},y_{n-2})...(xn−1​,yn−1​),(xn−2​,yn−2​)...,最终求得(x0,y0)(x_0,y_0)(x0​,y0​)

现在得到ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b),要求ax′+by′=m,gcd(a,b)∣max'+by'=m,\ gcd(a,b) \mid max′+by′=m,gcd(a,b)∣m,显然有x′=xmgcd(a,b)x'=x\frac{m}{gcd(a,b)}x′=xgcd(a,b)m​, y′=ymgcd(a,b)y'=y\frac{m}{gcd(a,b)}y′=ygcd(a,b)m​

# 常用式子

已知ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)一组解(x,y)(x,y)(x,y),其通解(x′,y′)(x',y')(x′,y′)为

f(x)={x′=x+bty′=y+at(t∈Z)f(x)=\left\{ \begin{aligned} x' = x+bt \\ y' = y+at \end{aligned} \right. (t \in Z) f(x)={x′=x+bty′=y+at​(t∈Z)

# 求最小正整数解

假设我们对ax+by=gax+by=gax+by=g找到一组解(xn,yn)(x_n,y_n)(xn​,yn​),那么对于ax+by=c(gcd(a,b)∣c)ax+by=c\ (gcd(a,b)\mid c)ax+by=c(gcd(a,b)∣c),求xxx最小正整数解

令g=gcd(a,b)g=gcd(a,b)g=gcd(a,b)

有xnacg+ynbcg=g∗cg=cx_n\frac{ac}{g}+y_n\frac{bc}{g}=g*\frac{c}{g}=cxn​gac​+yn​gbc​=g∗gc​=c,设k=c/gk=c/gk=c/g,因此x0=kxn,y0=kynx_0=kx_n, y_0=ky_nx0​=kxn​,y0​=kyn​

考虑让新解x1=x0−δxx_1=x_0-\delta_xx1​=x0​−δx​,为了使等式平衡,需要使y1=y0+δyy_1=y_0+\delta_yy1​=y0​+δy​

即:aδx=bδya\delta_x=b\delta_yaδx​=bδy​,因而δxδy=ba=b/ga/g(g=gcd(a,b))\frac{\delta_x}{\delta_y}=\frac{b}{a}=\frac{b/g}{a/g}\ (g=gcd(a,b))δy​δx​​=ab​=a/gb/g​(g=gcd(a,b))

注意这里不应当约掉ggg,因为δ\deltaδ越小,越能得到小的整数解

因而有t=b/g,xmin=(x0%t+t)%tt=b/g,x_{min}=(x_0\%t+t)\%tt=b/g,xmin​=(x0​%t+t)%t

# 洛谷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

# 模板

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

C++:

自己把上面的代码翻译一下就好。。

上次更新: 2021/02/24, 03:37:30
拉格朗日插值学习笔记
斐波那契数列学习笔记

← 拉格朗日插值学习笔记 斐波那契数列学习笔记→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式