定义
如果 a b ≡ 1 ( m o d p ) ab \equiv 1 \pmod p ab≡1(modp) ,则 a a a 和 b b b 在模 p p p 意义下互为乘法逆元,记作 a = i n v ( b ) a = \mathrm{inv} (b) a=inv(b) .
求法
拓展欧几里得(exgcd)
时间复杂度为 O ( log p ) O(\log p) O(logp)
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - a / b * x;
return d;
}
ll inv(ll a, ll p) {
ll x, y;
if(exgcd(a, p, x, y) != 1) return -1;
return ((x % p) + p) % p;
}
费马小定理 + 快速幂
若
p
p
p 是质数,且
gcd
(
a
,
p
)
=
1
\gcd (a, p) = 1
gcd(a,p)=1 ,则有
a
p
−
1
≡
1
(
m
o
d
p
)
a ^ {p-1} \equiv 1 \pmod p
ap−1≡1(modp) .
即
a
⋅
i
n
v
(
a
)
≡
1
≡
a
p
−
1
(
m
o
d
p
)
a \cdot \mathrm{inv}(a) \equiv 1 \equiv a ^ {p-1} \pmod p
a⋅inv(a)≡1≡ap−1(modp),于是有
i
n
v
(
a
)
≡
a
p
−
2
(
m
o
d
p
)
\mathrm{inv} (a) \equiv a ^ {p-2} \pmod p
inv(a)≡ap−2(modp) .
时间复杂度为 O ( log p ) O(\log p) O(logp)
#define ll long long
ll ksm(ll a,ll b,ll mod){
ll ans=1;
for(;b;b>>=1,a=a*a%mod)
if(b&1) ans=ans*a%mod;
return ans%mod;
}
ll inv(ll a, ll p) {
return ksm(a, p - 2, p);
}
线性递推
首先有
i
n
v
(
1
)
=
1
\mathrm{inv} (1) = 1
inv(1)=1 .
设
⌊
p
i
⌋
=
k
\lfloor \frac {p} {i} \rfloor = k
⌊ip⌋=k ,
p
m
o
d
i
=
r
p \bmod i = r
pmodi=r , 即
p
=
k
⋅
i
+
r
p = k \cdot i + r
p=k⋅i+r .
在模
p
p
p 意义下,有
k
⋅
i
+
r
≡
0
(
m
o
d
p
)
k \cdot i + r \equiv 0 \pmod p
k⋅i+r≡0(modp) .
等式两边同乘
i
n
v
(
i
)
⋅
i
n
v
(
r
)
\mathrm{inv} (i) \cdot \mathrm{inv} (r)
inv(i)⋅inv(r) , 得
k
⋅
i
n
v
(
r
)
+
i
n
v
(
i
)
≡
0
(
m
o
d
p
)
k \cdot \mathrm{inv} (r) + \mathrm{inv} (i) \equiv 0 \pmod p
k⋅inv(r)+inv(i)≡0(modp) .
移项并化简得
i
n
v
(
i
)
≡
−
⌊
p
i
⌋
⋅
i
n
v
(
p
m
o
d
i
)
(
m
o
d
p
)
\mathrm{inv} (i) \equiv - \lfloor \frac {p} {i} \rfloor \cdot \mathrm{inv} (p \bmod i) \pmod p
inv(i)≡−⌊ip⌋⋅inv(pmodi)(modp) .
时间复杂度为
O
(
n
)
O(n)
O(n)
Luogu - P3811 【模板】乘法逆元
//Luogu P3811 乘法逆元
#include<bits/stdc++.h>
#define N 3000006
#define ll long long
using namespace std;
ll n, p, inv[N];
int main() {
scanf("%lld%lld", &n, &p);
inv[1] = 1;
printf("%lld\n", inv[1]);
for(ll i = 2; i <= n; ++i) {
inv[i] = inv[p % i] * (p - p / i) % p;
printf("%lld\n", inv[i]);
}
return 0;
}