乘法逆元定义
假设a,x,b为整数,b>1,且有
a
x
≡
1
(
m
o
d
  
b
)
ax \equiv 1(\mod b)
ax≡1(modb)成立
那么a,x互为膜b的逆元
通俗一些,即两数乘积膜b等于1,则他们互为b的逆元
逆元算法求解
扩展欧几里得
既然已有同余式
a
x
≡
1
(
m
o
d
  
b
)
ax \equiv 1(\mod b)
ax≡1(modb)
那么我们可以将其转化为
a
x
+
b
y
=
1
ax+by=1
ax+by=1
可以用扩展欧几里得算法求出其最小非负整数解即为a在膜b意义下的逆元
不会扩展欧几里得算法看这里
扩展欧几里得 推导及应用
int exgcd(int a,int b,int &x,int &y)
{
if(b==0){x=1;y=0;return a;}
int gcd=exgcd(b,a%b,x,y);
int tp=x;
x=y; y=tp-a/b*y;
return gcd;
}
int x,y;
exgcd(a,b,x,y);
inv=(x%b+b)%b;
单次逆元的计算效率不错
费马小定理
若 p 为素数, a为正整数,且a,p互质,则有 a p − 1 ≡ 1 ( m o d    p ) a^{p-1}\equiv1(\mod p) ap−1≡1(modp)
对于
a
p
−
1
≡
1
(
m
o
d
  
p
)
a^{p-1}\equiv1(\mod p)
ap−1≡1(modp)
我们变形为
a
∗
a
p
−
2
≡
1
(
m
o
d
  
p
)
a*a^{p-2}\equiv1(\mod p)
a∗ap−2≡1(modp)
那么
x
=
a
p
−
2
x=a^{p-2}
x=ap−2%
p
p
p即为我们所要求的逆元
该算法可直接用快速幂计算
复杂度为log级别,效率高
注意p必须是质数
线性算法
首先有 1 − 1 ≡ 1 ( m o d    p ) 1^{-1}≡1(\mod p) 1−1≡1(modp)
设
p
=
k
∗
i
+
r
p=k*i+r
p=k∗i+r
(
r
<
i
(r<i
(r<i,
1
<
i
<
p
)
1<i<p)
1<i<p)
再将这个式子放到膜 p意义下得
k
∗
i
+
r
≡
0
(
m
o
d
  
p
)
k*i+r≡0(\mod p)
k∗i+r≡0(modp)
两边同时乘上 i − 1 i^{-1} i−1, r − 1 r^{-1} r−1得
k
∗
r
−
1
+
i
−
1
≡
0
(
m
o
d
  
p
)
k*r^{-1}+i^{-1}≡0(\mod p)
k∗r−1+i−1≡0(modp)
i
−
1
≡
−
k
∗
r
−
1
(
m
o
d
  
p
)
i^{-1}≡-k*r^{-1}(\mod p)
i−1≡−k∗r−1(modp)
i
−
1
≡
−
⌊
p
/
i
⌋
∗
(
p
m
o
d
  
i
)
−
1
(
m
o
d
  
p
)
i^{-1}≡-\lfloor p/i \rfloor*(p \mod i)^{-1}(\mod p)
i−1≡−⌊p/i⌋∗(pmodi)−1(modp)
于是我们得到一个线性递推算法
inv[1]=1;
for(int i=2;i<=n;++i)
inv[i]=(ll)(p-p/i)*inv[p%i]%p;
该算法复杂度O(n)
适用于需要求解一整组逆元的时候
逆元应用
对于
(
a
/
b
)
m
o
d
  
p
(a/b)\mod p
(a/b)modp这样的式子
显然不适用取膜运算律
所以我们将其改为
(
a
∗
i
n
v
[
b
]
)
m
o
d
  
p
(a*inv[b])\mod p
(a∗inv[b])modp