对于整数
,若存在整数
满足:
,则称
是
在模
意义下的乘法逆元,记为
首先,求解乘法逆元的方法有两种:
方法一:费马小定理
使用该方法的前提是:
必须是质数,并且
与
互质(
不是
的倍数)
费马小定理内容:
如果
是质数,那么对任意与
互质的整数
,有
c成立
那么
,所以
,即可用快速幂方法
方法二:扩展欧几里得
使用该方法的前提是:仅需要
与
互质
扩展欧几里得用于求解线性不定方程
的一组整数解
当
与
互质,即
时,原式变为求解
,两边同时对
取模,得到
,故
模
的正余数就是
的乘法逆元
方法一需要快速幂(已经倒背如流了),所以详细介绍扩展欧几里得算法:
扩展欧几里得算法是对欧几里得算法(辗转相除法)的扩展:
-
欧几里得算法核心:
,那么辗转下去,直到
,
-
扩展欧几里得的目标:在求
的同时,找到一组整数解
满足
(这个方程一定有解)
使用数学归纳法推导递归过程中解的传递关系:
递归的终止条件为
,那么方程为
,此时的一组解为
所以:
if(!b){
x = 1;
y = 0;
return a;
}
当
这一层为
下一层为
因为
,所以变为
,即
。
所以有
int g = exgcd(b, a % b, y, x); y -= (a / b) * x; return g;这里有些绕晕,更直观的代码:
int x1, y1; int g = gcd(b, a % b, x1, y1); x = y1; y = x1 - (a / b) * y1; return g;
所以扩展欧几里得算法的模板为:
int exgcd(int a, int b, int &x, int &y){
if(!b){
x = 1;
y = 0;
return a;
}
int g = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return g;
}
求解逆元总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
int exgcd(int a, int b, int &x, int &y){
if(!b){
x = 1;
y = 0;
return a;
}
int g = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return g;
}
signed main(){
HelloWorld;
int q; cin >> q;
while(q --){
int a, m; cin >> a >> m;
int x, y;
int g = exgcd(a, m, x, y);
cout << (x + m) % m << endl;
}
return 0;
}



京公网安备 11010502036488号