乘法逆元初探(扩展欧几里得)

情境引入
众所周知,有一个神奇的函数叫做gcd,中文名叫最大公约数
算法极其简单

int gcd(int a,int b){
    if(!b)return a;
    return gcd(b,a%b);
}

这种计算gcd的方法往往被称为辗转相除,但是,他的学名叫做“欧几里得算法”

但是,欧几里得这个数学家可只想用一个gcd来折磨人

于是,他又研究出一个叫做exgcd的东西,学名“扩展欧几里得”

例题: 洛谷 P1082同余方程

求关于x的方程a*x mod b = 1 的最小整数解

问题转化

我们观察题目这个等式,他的实质是在求ax+by=1这个等式的最小整数解

这里 y是我们新引入的某个整数,并且似乎是个负数才对。这样表示是为了用扩展欧几里得算法。我们将要努力求出一组 x,y 来满足这个等式。

看到这里,大家可能会有疑问:扩展欧几里得是用来求 ax + by = gcd(a,b) 中的未知数的,怎么牵扯到等于 1 呢?

原理是,方程 ax + by = max+by=m 有解的必要条件是 m mod gcd(a,b)=0。

由最大公因数的定义,可知 a 是 gcd(a,b) 的倍数,且 b是gcd(a,b) 的倍数,

若 x,y都是整数,就确定了 ax + by 是 gcd(a,b) 的倍数,

因为 m = ax + by,所以 m必须是 gcd(a,b) 的倍数,

那么 m mod gcd(a,b) = 0

可得出在这道题中,方程 ax + by = 1 的有解的必要条件是 1 mod gcd(a,b)=0。所以 gcd(a,b) 只能等于 1 了。这实际上就是a,b互质

扩展欧几里得

扩展欧几里得,简称扩欧,实在基础的欧几里得算法(gcd)的基础上实现的

代码:

# include <cstdio> 
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);
    k=x;
    x=y;
    y=k-a/b*y;
    return;
}

最后输出什么呢?
当然是x了,但是因为要mod一个数
所以我们要输出x%b
不对,再好好考虑考虑
x有可能是负数,所以我们要输出(x+b)%b

大功告成

小结

扩展欧几里得是一种非常常用的求逆元的方法

当然,你们有可能会问,你上面讲了这么多,和求逆元没什么关系啊

最后输出的就是逆元啊

发布了18 篇原创文章 · 获赞 3 · 访问量 1269

猜你喜欢

转载自blog.csdn.net/devout_/article/details/89417793