Exgcd 学习笔记

Exgcd 学习笔记

简介

这是扩展欧几里得算法,普通的欧几里得算法就是求两个东西的最大公因数.

这个东西可以求解一个方程:
ax+by=gcd⁡(a,b) ax+by=\gcd(a,b) ax+by=gcd(a,b)

一组可行解。

时间复杂度为 O(log⁡2(max⁡(a,b)))O(\log_2 (\max(a,b)))O(log2(max(a,b))).

算法逻辑

首先我们知道普通的欧几里得算法的代码是长这样的.

cpp 复制代码
int gcd(int x, int y) {return (y == 0) ? x : gcd(y, x % y);}

这是基于一个等式:
gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a,b)=\gcd(b,a \text{ mod } b)gcd(a,b)=gcd(b,a mod b)

其中 a mod ba \text{ mod } ba mod b 表示 aaa 除以 bbb 的余数.

现在我们回到原来的问题:

求解方程
ax+by=gcd⁡(a,b)ax+by=\gcd(a,b)ax+by=gcd(a,b)

然后我们考虑是否可以使用某种递推关系, 使用方程 ax2+by2=gcd⁡(a,b)ax_2+by_2=\gcd(a,b)ax2+by2=gcd(a,b) 去更新 ax1+by1=gcd⁡(a,b)ax_1+by_1=\gcd(a, b)ax1+by1=gcd(a,b).

然后我们现在的问题就是找到这两个方程的解的关系.

根据原来的欧几里得式子,我们可以得到一个等式:

我们设
bx2+(a mod b)y2=gcd⁡(a,a mod b) bx_2+(a \text{ mod } b)y_2=\gcd(a,a \text{ mod } b) bx2+(a mod b)y2=gcd(a,a mod b)

那么我们可以得到一个等式
ax1+by1=bx2+(a mod b)y2 ax_1+by_1=bx_2+(a \text{ mod } b)y_2 ax1+by1=bx2+(a mod b)y2

下面给出正确性证明

首先根据我们前面的设据,我们只需要证明
gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a, b) = \gcd(b, a \text{ mod } b)gcd(a,b)=gcd(b,a mod b)

这个东西的证明就是前面我写的欧几里得算法的证明.

然后我们拆右边的一坨式子:
bx2+(a mod b)y2=bx2+(a−b⌊ab⌋)y2 bx_2+(a \text{ mod } b)y_2=bx_2+(a-b\lfloor \frac{a}{b} \rfloor)y_2 bx2+(a mod b)y2=bx2+(a−b⌊ba⌋)y2

这个是显然的,可以根据除法定义得到, 然后我们继续拆式子:
bx2+(a−b⌊ab⌋)y2=bx2+ay2−b⌊ab⌋y2 bx_2+(a-b\lfloor \frac{a}{b} \rfloor)y_2=bx_2+ay_2-b\lfloor \frac{a}{b} \rfloor y_2 bx2+(a−b⌊ba⌋)y2=bx2+ay2−b⌊ba⌋y2

提出 bbb:
bx2+ay2−b⌊ab⌋y2=ay2+b(x2−⌊ab⌋y2) bx_2+ay_2-b\lfloor \frac{a}{b} \rfloor y_2=ay_2+b(x_2-\lfloor \frac{a}{b} \rfloor y_2) bx2+ay2−b⌊ba⌋y2=ay2+b(x2−⌊ba⌋y2)

然后直接写出我们的结论:
ax1+by1=ay2+b(x2−⌊ab⌋y2) ax_1+by_1=ay_2+b(x_2-\lfloor \frac{a}{b} \rfloor y_2) ax1+by1=ay2+b(x2−⌊ba⌋y2)

比较两边的系数, 我们可以得到
{y2=x1x2−⌊ab⌋y2=y1 \begin{cases} y_2=x_1 \\ x_2-\lfloor \frac{a}{b} \rfloor y_2=y_1 \end{cases} {y2=x1x2−⌊ba⌋y2=y1

那么我们考虑边界条件:

当 b=0b=0b=0 时,我们可以得到:
gcd⁡(a,b)=gcd⁡(a,0)=a\gcd(a, b)=\gcd(a, 0) = agcd(a,b)=gcd(a,0)=a.

那么
ax1=gcd⁡(a,0)=a ax_1=\gcd(a,0)=a ax1=gcd(a,0)=a

所以 x1=1,y1=0x_1=1, y_1=0x1=1,y1=0.

然后根据刚才的公式, 回代求解即可.

代码
cpp 复制代码
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;
}
相关推荐
三品吉他手会点灯1 小时前
C语言学习笔记 - 20.C编程预备计算机专业知识 - 变量为什么必须的初始化【重点】
c语言·笔记·学习
kobesdu1 小时前
【ROS2实战笔记-12】rosshow:终端里的盲文可视化与无头机器人的现场调试
笔记·机器人·ros·移动机器人
sakiko_1 小时前
UIKit学习笔记1-创建项目(使用UIKit)、使用组件
笔记·学习
Old Uncle Tom1 小时前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
会编程的土豆2 小时前
洛谷题单入门1 顺序结构
数据结构·算法·golang
生信碱移2 小时前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
智者知已应修善业2 小时前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
星幻元宇VR4 小时前
VR航空航天科普设备【VR时空直升机】
科技·学习·安全·生活·vr
_李小白4 小时前
【android opencv学习笔记】Day 2: Mat类(图片数据结构体)
android·opencv·学习
智者知已应修善业4 小时前
【51单片机按键调节占空比3位数码管显示】2023-8-24
c++·经验分享·笔记·算法·51单片机