扩展欧几里得

求解 ax+by=d 的解x和y。有解的条件为 d | gcd(a, b)

算法原理

假设现在我们已经得知了 by+(a%b)x=d 的解 y 和 x
by+(a%b)x=d 等价变形可以得到 ax+b(yabx)=d
所以说如果我们先计算了by+(a%b)x=d 的解 y 和 x,就可以得到我们最初想要计算的 ax+by=d 中的x和y
by+(a%b)x=d 的解 y 和 x分别为 y1 和 x1, 那么ax+by=d 中的 x = x1, y = y1 - a / b * x1

易错点

扩展欧几里得的解并不唯一,假设 ax+by=d 的一组解为 x1 和 y1,那么 x1+kbgcd(a,b)y1kagcd(a,b) 则是方程的通解,代入即可验证其正确性
为了后续叙述的方便,我们用t代替bgcd(a,b)
x1+kt是解,那么x1kt自然也是解,只需要y的解对应变化即可。那么当题目中要求我们求解x的最小正整数解时,接下来我们考虑应如何计算
分类讨论:

  1. x1为正数时,如果x1<t,此时的x1就是最小正整数解,因为如果再减t答案就会变为负数了;如果x1>t,操作应为while (x > t) x -= t;,等价于x %= t
  2. x1为负数时,如果操作应为while (x < 0) x += t;,等价于x = x % t + t,这里的操作是很巧妙的,第一次%t将x变化到绝对值小于t,这样再加t就能保证答案一定是正数且是最小的
    综上所述,可以发现,负数比正数多了一个+t的操作,为了统一两者,+t之后只需要再%t一次即可。最终操作为x = (x % t + t) % t

代码实现

/**
 * 求解ax + by = d
 * 无解输出impossible
 */
#include <iostream>

using namespace std;

// 不管题目怎么变化,exgcd只负责求解 ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    int gcd = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return gcd;
}
int main()
{
    int a, b, d, x, y;
    cin >> a >> b >> d;
    int t = exgcd(a, b, x, y);

    // 有解的条件为m是gcd(a, b)的倍数
    if (d % t) cout << "impossible" << endl;
    else cout << d / t * x << ' ' << d / t * y << endl;
    
    return 0;
}

用途

计算乘法逆元

posted @   0x7F  阅读(70)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示