【訓練題22:線性求逆元】【模板】乘法逆元 | 洛谷 P3811
阿新 • • 發佈:2020-12-27
技術標籤:【演算法/知識點 淺談】【各類ACM真題】演算法數論
難度
普
及
/
提
高
\color{yellow}普及/提高
普及/提高
板子題,給出兩種方法
題意
給
n
,
p
n,p
n,p
求出所有
i
∈
[
1
,
n
]
i\in[1,n]
i∈[1,n]在模
p
p
p 情況下的逆元
i
−
1
i^{-1}
i−1
一個一個求肯定是 O ( N log N ) O(N\log N) O(NlogN),容易超。這裡給出的兩種都為 O ( N ) O(N) O(N)的。
資料範圍
n
≤
3
×
1
0
6
n\le 3\times10^6
n≤3×106
n
<
p
<
20000528
n<p<20000528
n<p<20000528 且
p
p
p 是質數
方法1:階乘逆元法
- 我們可以
O
(
N
)
O(N)
O(N) 預處理出所有
(
i
!
)
−
1
(i!)^{-1}
(i!)−1,方法如下:
- 首先算出 n ! n! n! ,可以直接遞推獲得。
- 再算出
(
n
!
)
−
1
(n!)^{-1}
(n!)−1,使用費馬小定理即可,即
(
n
!
)
−
1
≡
(
n
!
)
p
−
2
(
m
o
d
p
)
(n!)^{-1}\equiv(n!)^{p-2}\pmod{p}
- 接下來,遞推 ( i ! ) − 1 = ( ( i + 1 ) × ( i + 1 ) ! − 1 ) % p (i!)^{-1}=((i+1)\times(i+1)!^{-1})\% p (i!)−1=((i+1)×(i+1)!−1)%p 即可。
- 計算 ( i ) − 1 = ( i ! ) − 1 × ( i − 1 ) ! % p (i)^{-1}=(i!)^{-1}\times (i-1)!\%p (i)−1=(i!)−1×(i−1)!%p 即可。
方法2:線性求逆元
- 我們求模
p
p
p 下
i
i
- p = i × k + r p=i\times k+r p=i×k+r,其中 0 < r < i 0<r<i 0<r<i
- 其中 k = p i k=\frac{p}{i} k=ip為商, r = p % i r=p\%i r=p%i為餘數。
- 接下來我們寫出同餘等式的表示式子:
- i × k + r ≡ 0 ( m o d p ) i\times k+r\equiv 0\pmod{p} i×k+r≡0(modp)
- 兩邊同時除以 r × i r\times i r×i,是為了得到 i − 1 i^{-1} i−1這一項在單獨的一邊。我們得到:
- r − 1 × k + i − 1 ≡ 0 ( m o d p ) r^{-1}\times k+i^{-1}\equiv 0\pmod{p} r−1×k+i−1≡0(modp) 移項可得:
- i − 1 ≡ − r − 1 × k ( m o d p ) i^{-1}\equiv -\ r^{-1}\times k\pmod{p} i−1≡−r−1×k(modp) 我們把 r r r 和 k k k 帶入可得:
-
i
−
1
≡
−
(
p
%
i
)
−
1
×
p
i
(
m
o
d
p
)
i^{-1}\equiv -\ (p\%i)^{-1}\times \frac{p}{i}\pmod{p}
i−1≡−(p%i)−1×ip(modp)
接下來寫成程式碼即可。
注意一下,由於裡面有負號,取模意義下不會出現負號,負數取模完加上模數再取模即可。
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/
const int MAX = 3e6+50;
const ll MOD = 19260817;
ll Inv[MAX];
int main()
{
int n,p;
scanf("%d%d",&n,&p);
Inv[1] = 1;
puts("1");
for(int i = 2;i <= n;++i){
Inv[i]=(p-(p/i)*Inv[p%i]%p)%p;
printf("%lld\n",Inv[i]);
}
return 0;
}