逆元:方程ax≡1(mod n)的一个解x,称x为a模m的逆。
逆元的一个重要应用是求除法的模:
如求(a/b)%m=?
设b的逆元是k,则有(a/b)%m=((a/b)%m)((bk)%m)=(a/b*bk)%m=(ak)%m
因此求(a/b)%m的值相当于求b的逆元
求逆元的几种方法:
1、扩展欧几里得算法
求解方程ax≡1(mod m)相当于求解ax+my=1(ax-1是m的整数倍,设y是倍数,那么ax-1=my,即ax+my=1,y可以是负数);
有解的条件是:gcd(a,m)=1,即a和m互素。
void extend_gcd(int a,int b,int &x,int &y) {
if(b==0) {
x=1,y=0;
return;
}
extend_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
int mod_inverse(int a,int m) {
int x,y;
extend_gcd(a,m,x,y);
return(m+x%m)%m; //x可能是负数,需要处理
}
2、费马小定理
设 m 是素数 ,且 a%m≠0,那么 a^(m−1)≡1(mod m) 。
那么a*a^(m-2)≡1(mod m) ,则其逆元就是a^(m-2)。可以用快速幂求解逆元
typedef long long ll;
ll quick_pow(ll b, ll n) {
ll ans = 1, po = b;
while(n) {
if(n & 1) ans = (ans * po) % mod;
po = (po * po) % mod;
n >>= 1;
}
return ans;
}
3、线性求解逆元
在模质数p下,求1~n逆元,n<p。可以O(n)求出所有逆元。
假设 p=k*i+j, (1<i<p,j<i)
我们可以得知 p=k∗i+j≡0(mod p)
对两边同时乘以(ij)^(-1)可以得到 i^(-1)+k*j^(-1)=0
那么变化可得 i^(-1)=-k*j^(-1) (1/i 就为i的逆元,1/j 就为j的逆元)
且已知1^(-1)≡1(mod p)
故可以得递推式a[i]=-(p/i)*a[p%i]
a[1]=1
另外:1->p模p的所有逆元值对应1->p中所有的数,比如p=7,那么1->6对应的逆元是 1 4 5 2 3 6
void inverse(int n, int p) {
a[1] = 1;
for (int i=2; i<=n; ++i) {
a[i] = (ll) (p - p / i) * a[p%i] % p;
}
}
参考链接:https://blog.csdn.net/guhaiteng/article/details/52123385
https://www.cnblogs.com/lifehappy/p/12763635.html