扩展欧几里得求逆元

[牛客网]A Number Theoretical Problem
题目链接:https://ac.nowcoder.com/acm/problem/207599

这貌似是一道求逆元的模板题,但是。。。
逆元是什么啊!!!扩展欧几里得是什么啊!!!
于是我今天花了一下去看别人的博客,一脸懵逼的进去,一脸懵逼的出来。
其实有很多地方我都搞不明白,但也管不了那么多啦,把我搞明白的讲出来就可以了

**欧几里得算法**

首先我们都知道欧几里得算法(也叫辗转相除法)能求出两个数a,b的最大公约数,即gcd(a,b)=gkd(b,a%b)。

代码实现如下:

int gcd(int a,int b){
    if(b==0) return a;
    int ans=gcd(b,a%b);
    return ans;
}

扩展欧几里得
再次基础上的扩展欧几里得能快速求ax+by=gcd(a,b)一个二元一次方程的一个特解
当欧几里得算法递归到最后一层,即b=0时,那么gcd=a,这就很容易得到一个特解 x=1,y=0,即ax+by=a1+b0=a=gcd
得到特解x=1,y=0,在通过递归的返回,再来一层一层推出原本 ax+by=gck,的一组特解
关于如何推出上一层的特解呢?在这里我们把上一层的解x,y。当前层已知的解为x1,y1
在这里的一个结论是 a%b=a-(a/b)*b (这里的 “/” 指的是整除,例如 5/2=2 , 1/3=0)由于上一层的gcd(a,b)等于当前层的gcd(b,a%b)

gcd(b,a%b)
=b
x1+(a%b)*y1

=b*x1+(a-(a/b)*b)*y1

=bx1+ ay1-(a/b)by1

=a*(y1)+b*(x1-(a/b)*y1)

又因为gcd(a,b)=ax+by,即这两式子相等,通过比较得 x=y1,y=x1-(a/b)*y1。

代码实现如下:

int gcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1,y=0;  \\  一组特解
        return a;
    }
    int ans=gcd(b,a%b,x,y);
    int t=x;        \\由最后一层的一组特解向上推
    x=y;    
    y=t-(a/b)*y;
    return ans;
}

如果只能扩展欧几里快速求ax+by=gcd(a,b)一个二元一次方程的一个特解,可能会说:“ 就这???
这里我们就要知道扩展欧几里快速求乘法逆元 (逆元也有啥用呀 )
然后就是逆元的定义什么叫乘法逆元?

ax≡1(mod n) (≡为同余符号,即(ax)mod n==1 mod n)
这里,我们称 x 是 a 关于 n 的乘法逆元

判断逆元是否存在为gcd(a,n)是否等于1,等于即存在,否则不存在。
我们可以把他写成一个表达式为:ax+by=1(这里设b=n)
于是求逆元就要求这个二元一次方程组,则通过上面所说的扩展欧几里得
但是有无数解,但一般会让你求最小解x0,其实x0mod n就是最小解(这我真搞不明白)
考虑到x0可能是为负数,那我们先对其取模,x0mod n ,但x0还是负数,我们再加上其n,最后再取模。即 x0=(x0%n+n)%n

于是对于牛客上那道求逆元的模板题我们就迎刃而解了

代码实现如下

#include <iostream>
typedef long long LL;
using namespace std;
LL exgcd(LL a,LL b,LL &x,LL &y);
int t;
LL y,p;
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld %lld",&y,&p);
        LL x=0,k=0;
        LL ok=exgcd(y,p,x,k);
        if(ok==1) printf("%lld\n",(x%p+p)%p);
        else printf("-1\n");
    }
}
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    int ans=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-(a/b)*y;
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
欧几里得算法是一个用于计算两个整数的最大公约数的算法扩展欧几里得算法可以在得最大公约数的同时计算出满足贝祖等式 ax + by = gcd(a,b) 的整数解 x 和 y,其中 a 和 b 是输入的整数。 扩展欧几里得算法可用于解模反元素(逆元),其中逆元是指某个整数关于模数的乘法逆元素。 下面是我用C语言实现扩展欧几里得算法逆元的示例代码: ``` #include <stdio.h> int extended_gcd(int a, int b, int *x, int *y) { if (b == 0) { *x = 1; *y = 0; return a; } int x1, y1; int gcd = extended_gcd(b, a % b, &x1, &y1); *x = y1; *y = x1 - a / b * y1; return gcd; } int mod_inverse(int a, int m) { int x, y; int gcd = extended_gcd(a, m, &x, &y); if (gcd != 1) { printf("逆元不存在\n"); return -1; // 逆元不存在 } int inverse = (x % m + m) % m; return inverse; } int main() { int a, m; printf("请输入要逆元的整数a和模数m:"); scanf("%d %d", &a, &m); int inverse = mod_inverse(a, m); if (inverse != -1) { printf("%d关于模数%d的逆元是:%d\n", a, m, inverse); } return 0; } ``` 这是一个简单的扩展欧几里得算法逆元的实现,首先通过`extended_gcd`函数出`a`和`m`的最大公约数,并计算满足贝祖等式的整数解`x`和`y`。如果最大公约数不为1,则逆元不存在。若最大公约数为1,则通过模的方式计算`x`关于模数`m`的逆元。代码中的`mod_inverse`函数用于调用`extended_gcd`函数,并处理逆元不存在的情况。最后,通过用户输入需要逆元的整数`a`和模数`m`,并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值