扩展欧几里得(exgcd)通解及其证明

exgcd求ax + by = gcd(a, b)中x和y的通解(下面简称通解)

新整理的文章在这,可能不全,这是老文章,新文章

什么是通解
我们知道二元一次方程, 是如果只有一个式子, 那么解会有无数个 
而通解就是指让我们只找到一个解就可以推出其他所有解的式子
(注意本证明极其复杂, 请直接背模版或感性理解)

知道了定义下面就是推式子了
首先设x, y是ax + by = gcd(a, b)的一个解
那么有y = (gcd(a, b) - ax) / b (1), 且y, x, a, b是整数

再设一个解x0 = x + k (2), k和x0是整数, 
那么有 a*x0 + b*y0 = gcd(a, b);
y0 = (gcd(a, b) - a*x0) / b (3)
由(3)和(2)得 
y0 = (gcd(a, b) - ax - ak)/b <==> y0 = (gcd(a, b) - ax)/b - a/b * k (4)

由(4)和(1)得 y0 = y - a/b * k (5)
我们要保证y0是整数, y又是整数, 那么a/b * k就是整数
设d = gcd(a, b);
a = a' * d, b = b' * d, 这里a', b'互质(非常基本的知识点, 如果他们不互质, d就可以
通过a', b'的公约数变大, 这就和我们d是最大公约数就矛盾了, 所以a'和b'互质)
a/b * k == a'/b' * k,
因为a'和b'互质, 那么a'/b' * k 要是想是整数的话, k只能是b'的倍数(k == 0时整个就是
0也是整数, 满足要求)
不然就消不掉a'/b'的分母b', 就会产生小数, 就不是整数了
so, k = n*b', (n是任意整数), 
又因为b' * d = b  ==> b' = b / d
这样k = n*b/d
所以x0 = x + n*b/d (6)
通过(5)和(6)可得 y0 = y - n*a/d (7) // 这里是-, 不是+
至此通解就出来了
x0 = x + n*b/d
y0 = y - n*a/d
更常见的是这样的
x0 = x + k*b/d (当然这里的k不是上面的k, 是和n一样的任意整数)
y0 = y - k*a/d

附带最小正整数解就是 x % (b / d); 
因为会有x是负数的情况, 所以更准确的应该是
(x % (b/d) + b/d) % (b/d)
就相当于把所有的k*b/d给删掉, 剩下的就是最小的正整数解

感谢https://blog.csdn.net/qq_41779251/article/details/82634045这篇文章


#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long LL;

int n, m;

int exgcd(int a, int b, LL &x, LL &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main()
{
    LL x, y, d;
    cin >> n >> m;
    d = exgcd(n, m, x, y);
    cout << (x % m + m) % m << endl; // 这里d是1所以不除也没事
    return 0;
}

补充

    exgcd二元一次等式, 扩大后判断是否有整数解,(小数解都是有的, 但是小数解不符合我们要求)
    首先exgcd求出的等式ax + by = d肯定是有整数解的, 但是等式两边扩大非整数倍后就不一定了, 一定得是整数倍, 
    如果是小数比如1/2就不一定对了, 比如6x + 2y = 2合法, 但是6*x0 + 2*y0 = 1就是无整数解情况(x变为x/2 == x0, 对于后式是求x0, 而非x)
    ax + by = k, k满足扩大d整数倍的条件就是 k % d == 0, k = n * d
    k % d == 0这就是扩大后判断是否有整数解的充要条件
    
    我们知道通解是x = x0 + k*b/gcd(a, b), 设m = gcd(a, b), t = d / gcd(a, b)
    等式扩大了, 但是通解不变, 因为a没变, b没变, a(x*t + k*b/m) + b(y*t - k*a/m) = d
    axt + bxt + akb/m - bka/m = d
    axt + bxt = d, 可以发现等式两边没变
    也就说明通解可行, 对于其他情况也可以这样证明, 通解的可行性
posted @ 2024-03-24 21:36  blind5883  阅读(23)  评论(0编辑  收藏  举报