-拓展欧几里得,以及乘法逆元


参考的大佬博客:详解扩展欧几里得算法(扩展GCD) - Seaway-Fu - 博客园 (cnblogs.com)

(32条消息) 扩展欧几里得算法_zthgreat的博客-CSDN博客_扩展欧几里得算法

扩展欧几里得算法 - 知乎 (zhihu.com)

基本都是别人的内容,主要用于自用

欧几里得

欧几里得算法基于gcd(a,b)=gcd(b%a,a)(相当于a,b相互减去对方的个数,a%b=aba/ba%b=a−b⌊a/b⌋)用于求解两数最大公约数

 

在这里我们先引入裴蜀定理

裴蜀定理

        对于任意的整数a,b,都存在一对整数x,y,使得ax+by=gcd(a,b)ax+by=gcd(a,b)成立

假设存在一对整数x,y,使得其一定会满足b×x+(a%b)×y=gcd(b,a%b)b×x+(a%b)×y=gcd(b,a%b), 因为a%b=aba/ba%b=a−b⌊a/b⌋,所以有以下的推导:

                  b×x+(a%b)×y=gcd(b,a%b)=bx+(aba/b)y=ayb(xa/by)

可得结论:ax+by=gcd(a,b)

那么可以推出:如果一个数mm满足:ax+by=mm,那么这个mm一定是gcd(a,b)的倍数。

那么对于一个经典方程ax+by=1ax+by=1,利用裴蜀定理,我们有:gcd(a,b)=1,即a,b一定互质。

递归版本

#include<stdio.h>
int main()
{
    int a,b,s,t,gcd;
    int exgcd(int a,int b,int *x,int *y);
    while(scanf("%d%d",&a,&b)!=EOF)
    {
        gcd=exgcd(a,b,&s,&t);
        printf("%d %d\n",s,t);
    }
    return 0;
}
int exgcd(int a,int b,int *x,int *y)//扩展欧几里得算法;
{
    if(b==0)
    {
        *x=1;
        *y=0;
        return a;
    }
    int ret=exgcd(b,a%b,x,y);
    int t=*x;
    *x=*y;
    *y=t-a/b*(*y);
    return ret;
}

 

非递归版本

int exgcd(int a,int b,int &x,int &y)
{
    int xi_1,yi_1,xi_2,yi_2;
    xi_2=1,yi_2=0;
    xi_1=0,yi_1=1;
    x=0,y=1;
    int r=a%b;
    int q=a/b;
    while (r)
    {
        x=xi_2-q*xi_1;
        y=yi_2-q*yi_1;
        
        xi_2=xi_1;
        yi_2=yi_1;
 
        xi_1=x,yi_1=y;
        a=b;
        b=r;
        r=a%b;
        q=a/b;
    }
    return b;
}

用途1:解不定方程ax+by=gcd(a,b)

由于是是不定式,x和y只需要得到返回值即可

用途二:解乘法逆元

当我们用扩展欧几里得算法找到一组 x 和 y 满足 [公式] 时,就可以得出 [公式] ,也就是说 x 是 a 的乘法逆元。

显然,如果 x 是 a 的乘法逆元,那么所有的 [公式] 也是 a 的乘法逆元。这表明,一定有 a 的一个乘法逆元在区间 [公式] 内。

这是找到 n 在模 p 下的乘法逆元的一个算法,使用了上面的 exgcd:

int inv(int n, int p) {
    int x, y;
    if(exgcd(n, p, x, y) == 1) {
        x = x % p;
        return x >= 0 ? x : p + x;
    } else {
        return -1;
    }
}

 

如果返回 -1,表示乘法逆元不存在。

         

 

 

 

posted on 2022-04-14 16:02  zesure  阅读(14)  评论(0编辑  收藏  举报

导航