定义
如果存在a,x,b满足线性同余方程ax ≡ 1(mod b)(即b除以整数ax − 1,或者换句话说,将ax除以整数b之后的余数为1),则我们称:
a关于模b的乘法逆元为x,表示为a ≡ x-1 (mod b);
x关于模b的乘法逆元为a,表示为x ≡ a-1 (mod b)
附:该运算的基本用途是在可能的情况下求解形式的线性同余ax≡b(mod m)
条件
在同余方程中,若a 与b互质, 则一定存在一个正整数解x, 满足x < b;若a 与b 不互质, 则一定不存在正整数解x.所以逆元要求a与b互质。
求解
扩展欧几里得
扩展欧几里得算法是用来解决:ax+by = gcd(a,b),求x和y的问题。我们的逆元式子为ax ≡ 1(mod b),求x,根据它的实际定义,我们首先可以表示为
ax%b=1
接着变换为
ax-by=1
假设y<0
ax+by=1
这样我们就能够利用扩展欧几里得算法求解了。
例如 7x=1(mod 4),求x
def ext_euclid(a, b):
if b == 0:
return 1, 0
else:
x, y= ext_euclid(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y
x,y = ext_euclid(7,4)
print (x,y)
快速幂法
在ab ≡ 1(mod p)中求解
这个要运用费马小定理 :
若p为质数,a为正整数,且 a、p互质,则ap-1≡1(mod p)。
因为ax ≡ 1(mod b);
所以ax ≡ ab-1(mod b)(根据费马小定理)
所以x ≡ ab-2(mod b);
然后我们就可以用快速幂来求了。
inline int qpow(long long a, int b) {
int ans = 1;
a = (a % p + p) % p;
for (; b; b >>= 1) {
if (b & 1) ans = (a * ans) % p;
a = (a * a) % p;
}
return ans;
}
线性求逆元
例:ab ≡ 1(mod p),求b
p%a = p-(p/a)*a; 在c++中/为整除
(p/a)*a = p-(p%a); 换下位置
(p/a)*a = -(p%a); 在模p意义下p可以约掉,可以没有这一步
a = -(p%a)/(p/a); 再换一下位置
a-1 = -(p%a)-1*(p/a);
所以a-1可以用(p%a)-1推出,所以就可以用递推式来推出1到a的所有数的逆元。
求解多个逆元
int inv[MAXN];
void INV(int a,int p)//线性求到a的逆元
{
inv[1] = 1;
for (int i=2; i<=a; ++i)
inv[i] = (-(p/i))*inv[p%i]%p;
}
求解一个逆元
int INV(int a)//线性求a的逆元
{
if (a==1) return 1;
return ((-(p/a)*INV(p%a))%p);
}
参考
https://oi-wiki.org/math/inverse/
https://www.cnblogs.com/mjtcn/p/7241896.html
https://oi-wiki.org/math/linear-equation/
https://en.wikipedia.org/wiki/Modular_multiplicative_inverse