AcWing 877. 扩展欧几里得算法

题目传送门

一、理解和感悟

1、裴蜀定理

裴蜀定理(或贝祖定理)得名于法国数学家艾蒂安·裴蜀,说明了对任何整数(a)(b)和它们的最大公约数(d),关于未知数(x)(y)的线性不定方程(称为裴蜀等式):若(a),(b)是整数,且(gcd(a,b)=d),那么对于任意的整数(x),(y),(ax+by)都一定是(d)的倍数,特别地,一定存在整数(x),(y),使(ax+by=d)成立

推论:(a),(b)互质的充分必要条件是存在整数(x),(y)使(ax+by=1)

举个栗子:
(2x+y=3)

那么(a=2),(b=1),(m=3),(gcd(2,1)=1),(3)(1)的倍数,所以这个方程一定要整数解。
比如(x=1),(y=1)就是一个整数解,还可以有(x=-2),(y=7)也是一组整数解。

注意:如果一个二元一次方程有正整数解,那么不只是一组解。

再举一个栗子:
(4x+2y=5)
有没有整数解呢?没有,因为(a=4,b=2,m=5,gcd(4,2)=2,5)是除不开(2)的,所以没有整数解!

2、如何求贝祖数?

什么是贝祖数?
比如:(2x+y=3),那么符合这个等式的(x=1),(y=1)就是一组贝祖数。

在计算机算法中,可以使用扩展欧几里得算法求贝祖数

举个栗子:
(104x+40y=8) ,有没有合适的(x,y),也就是求贝祖数。

通过贝祖定理看一下,它是不是有解: (gcd(104,40)=8),(8)(8)的倍数,所以此方程一定有解,那么解是什么呢?

QQ截图20210301141004.png

扩展欧几里得算法的推导过程:

我们先来求方程 (ax+by=gcd(a,b))的解

((1))、当 (b=0)

(ax+by=gcd(a,0)),也就是:(ax=gcd(a,0)=a),所以(x=1)

那么(y)呢?因为普遍意义上的求贝祖数,一般是指不小于零的一组解,那么不小于(0)的第一个可能(y)值就是:(y=0),所以,可以将(x=1,y=0)做为一组特解返回,也就是返回了一组“不小于零的贝祖数”。

((2))、当 (b≠0)

(ecause gcd(a,b)=gcd(b,a\%b))

并且(① ax+by=gcd(a,b))

( herefore bx′+(a\%b)y′=gcd(a,b))

(ecause a−⌊a/b⌋∗b=a\%b)

( herefore bx′+(a−⌊a/b⌋∗b)y′=gcd(a,b))

变形一下:

(② ay′+b(x′−⌊a/b⌋∗y′)=gcd(a,b))

对比(① ②)系数:

( herefore) (x=y′,y=x′−⌊a/b⌋∗y′)

因此可以采取递归算法 先求出下一层的(x′)(y′) 再利用上述公式回代即可

二、完整代码


#include <bits/stdc++.h>

using namespace std;

/**
 * 功能:扩展欧几里得算法模板
 * @param a 第一个数
 * @param b 第二个数
 * @param x 贝祖数x 最小非负整数
 * @param y 贝祖数y 最小非负整数
 * @return
 */
int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}


int main() {
    //优化输入
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    while (n--) {
        int a, b;
        cin >> a >> b;
        int x, y;
        exgcd(a, b, x, y);
        printf("%d %d
", x, y);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/littlehb/p/15375125.html