对于整数,若存在整数满足:,则称 在模意义下的乘法逆元,记为
首先,求解乘法逆元的方法有两种:
方法一:费马小定理
使用该方法的前提是:必须是质数,并且互质(不是的倍数)
费马小定理内容:
如果是质数,那么对任意与互质的整数,有c成立
那么,所以,即可用快速幂方法

方法二:扩展欧几里得
使用该方法的前提是:仅需要互质
扩展欧几里得用于求解线性不定方程的一组整数解
互质,即时,原式变为求解,两边同时对取模,得到,故的正余数就是的乘法逆元

方法一需要快速幂(已经倒背如流了),所以详细介绍扩展欧几里得算法:
扩展欧几里得算法是对欧几里得算法(辗转相除法)的扩展:
  1. 欧几里得算法核心:,那么辗转下去,直到
  2. 扩展欧几里得的目标:在求的同时,找到一组整数解满足(这个方程一定有解)
使用数学归纳法推导递归过程中解的传递关系:
递归的终止条件为,那么方程为,此时的一组解为
所以:
if(!b){
    x = 1;
    y = 0;
    return a;
}
,即中间递归过程:
这一层为
下一层为bx^{'}+(a\%b)y^{'}=gcd(b,a\%b)
因为a\%b=a-\lfloor\frac{a}{b}\rfloor\times b,所以变为bx^{'} +(a-\lfloor\frac{a}{b}\rfloor\times b)y^{'}=gcd(b,a\%b),即
所以有
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;
}