求解逆元(C/C++)
本文最后更新于1016 天前,其中的信息可能已经过时,如有错误请发送邮件到17671220626@139.com

1. 逆元的原理

(a + b) % p = (a % p + b % p ) % p
(a – b) % p = (a % p – b % p ) % p
(a * b) % p = (a % p * b % p ) % p
(a / b) % p = (a % p / b % p) % p
 1.1. 这就是四种常用的求余的运算,可以发现前面三种其实都是正确的,而对于第四种这是不正确的,我们必须要先除得到结果再去计算,这就可能导致如果里面还有乘法,就必须要先进行连乘然后再整除,而当进行多个数的连乘的时候就可能爆掉long long 的一个数值范围所以我们想要将第四个式子进行一个转换,能不能将 a / b 转换成为 a * b(逆元) % p进行计算。将其称为逆元b称为b在模p上的乘法逆元
 1.2. 逆元存在的充要条件时 b 和 p 互质
 1.3. 快速幂求解逆元:借助费马小定理,必须保证 p 为质数
 1.4. 扩展欧几里得求逆元:可以不要求 p 为质数,从逆元充要条件 gcd(b, p) == 1 开始推理

2. 快速幂求解逆元

 2.1 快速幂介绍
 原理:

在这里插入图片描述
 代码:

LL qmi(LL a, LL b, LL mod){ // a 的 b 次方 取模 mod 
    LL res = 1;
    while(b){ 
        if(b & 1) res = res * a % mod; // 不断得到b的最低位,看其是否为1,为1就可以乘上
        b >>= 1; // 删去最低位的1
        a = a * a % mod; // 得到相应位上的 a 的次方大小
    }
    return res;
}

 2.2 费马小定理推出逆元公式
 原理:

在这里插入图片描述

 2.3 代码运行展示
 a. 快速幂代码展示

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int qmi(LL a, LL b, LL mod){
    LL res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int main(){
    cout << "假设求解 4 的 3 次方, 取膜 100 的结果" << endl;
    int a = 4, b = 3, mod = 100;
    cout << qmi(a, b, mod) << endl;
}

在这里插入图片描述

 b. 快速幂求解逆元代码展示
 只需要利用快速幂改为 求解 b ^(mod – 2) 的逆元即可

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int qmi(LL a, LL b, LL mod){
    LL res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

int main(){
    cout << "假设求解 4 取模 3 的逆元" << endl;
    int a = 4, b = 4, mod = 3;
    cout << qmi(b, mod - 2, mod) << endl; //
}

在这里插入图片描述

3. 扩展欧几里得求解逆元

 3.1 扩展欧几里得介绍
 原理:

在这里插入图片描述

#include<iostream>
using namespace std;
int x, y;
void exgcd(int a, int b){ // void exgcd(int a, int b, int &x, int &y)
    if(b == 0){
        x = 1, y = 0;
        return ;
    }
    exgcd(b, a % b);
    int xx = x, yy = y;
    x = yy;
    y = xx - a / b * yy;
    /* 优化写法 将上面四个语句可以换成这两个语句
    exgcd(b, a % b, y, x);
    y = y - a / b * x;
    */
}

int main(){
    int n, a, b;
    cin >> n;
    while(n -- ){
        cin >> a >> b;
        exgcd(a, b);
        // 优化写法 exgcd(a, b, x, y);
        cout << x << ' ' << y << endl;
    }
}

 3.2 扩展欧几里推逆元公式
 原理:
相当于求解exgcd(a, m, x, y) 最终的 x 就是结果


 3.3 代码运行展示

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main(){
	int a, m;
    a = 4, m = 3;
    int x, y, d;
    d = exgcd(a, m, x, y);
    if(d == 1){ // 保证互质才会有逆元
        cout << "4 % 3 的逆元大小为" << endl;
        cout << ((LL)x % m + m) % m << endl; // 保证输出的逆元为正整数
    }
    else{
        puts("不存在逆元");
    }
}

在这里插入图片描述

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇