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("不存在逆元");
}
}