扩展欧几里得算法

Posted lbzbk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扩展欧几里得算法相关的知识,希望对你有一定的参考价值。

扩展欧几里得算法

前置条件:需要掌握裴蜀定理和欧几里得算法

裴蜀定理:
对于不全为0的整数a, b,一定有整数x, y,使得ax + by = gcd(a, b)


欧几里得算法:
gcd(a, b) == gcd(b, a % b)

假设有组特解x0, y0,使得ax0 + by0 = gcd(a, b)
则必有bx1 + (a % b)y1 = gcd(b, a % b) = gcd(a, b)
其中(a % b) = a - a / b * b
整理得:b(x1 - a / b * y1) + ay1 = ax0 + by0
即:y0 = x1 - a / b * y1, x0 = y1
所以x0 是由 y1转化而来, y0 是由 x1 - a / b * y1转化而来,因此递归时使用exgcd(b, a % b, y, x), y -= a / b * x

若要使ax + by = n(n为ax + by可以取到的数)
设d = gcd(a, b), 那么n % d == 0,n一定是d的倍数
他的特解是x0, y0,而通解则是:
x = n / d * x0 + k * b / d(k为任意整数)
y = n / d * y0 + k * a / d

#include <iostream>

using namespace std;

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() 
    int n;
    cin >> n;
    while (n --) 
        int a, b, x, y;
        cin >> a >> b;
        exgcd(a, b, x, y);
        cout << x << \' \' << y << endl;
    
    
    return 0;

扩展欧几里得算法+推论

什么是扩展欧几里得?

扩展欧几里得算法是建立在欧几里得算法(gcd)之上。

首先,我们知道有(a*x+b*y=gcd(a,b))

我们怎么求这个(x,y)呢?

这时候我们就得使用exgcd算法,我们来推导一下吧!

(a*x+b*y=gcd(a,b))
(a*x+b*y=gcd(b,a\% b))
(a*x+b*y=b*x'+(a- left lfloor frac{a}{b} ight floor*b)*y')
(a*x+b*y= a*y'+b*(x'-left lfloor frac{a}{b} ight floor*y'))

因此,根据系数对应,我们得到了

(x=y'),(y=x'-left lfloor frac{a}{b} ight floor*y')

那这个式子我们显然可以在递归里面顺带算出来嘛。

再想一想,我们gcd的递归出口为(b=0),即(a*x=gcd(a,b)),所以说我们的(x,y)的递归出口也为(x=1,y=0)

代码大概长这样qwq:

long long exgcd(long long A,long long B,long long &x,long long &y)
{
    if(B==0) 
    {
        x=1,y=0;
        return A;
    }
    long long t=exgcd(B,A%B,x,y),tx=x;
    x=y;
    y=tx-(A/B)*y;
    return t;
}

酱紫,我们就求出了(x,y)的一组解(x_0,y_0)


进一步推导

如果我们要求x的最小正整数解,那不免要求x的通项公式。

首先我们的推导建立在已经求出了一组((x_0,y_0))使得(a imes x+b imes y=gcd(a,b))

我们要求的(x)的通项公式是建立在(x_0)之上的,我们假设(x=x_0+p)(y=y_0-q)

现在问题就变为了如何求这个(p)

原式变为:
[a(x_0+p)+b(y_0-q)=gcd(a,b)]

展开得:
[a*x_0+a*p+b*y_0-q*b=gcd(a,b)]

与原式(a*x_0+b*y_0=gcd(a,b))相减得
[ap=bq]

[p=frac{b*q}{a}]

我们设(d=gcd(a,b)),有(a=a'*d),(b=b'*d)

将上一个式子上下同时除以(d)
[p=frac{b'*q}{a'}]

因为(p)为正整数,因此我们的(q)至少等于(a')才能使得(p)的取值最小
[p=b*frac{a'}{a}=b*frac{1}{d}=b*frac{1}{gcd(a,b)}]

解毕,我们得到了(x)的通项公式(x=x_0+k*frac{b}{gcd(a,b)})

.

完结撒花(*′???`)?

以上是关于扩展欧几里得算法的主要内容,如果未能解决你的问题,请参考以下文章

利用扩展的欧几里得算法求逆元

欧几里得算法和扩展欧几里得算法

《夜深人静写算法》数论篇 - (10) 扩展欧几里得定理

扩展欧几里得算法

扩展欧几里得算法

扩展欧几里得算法+推论