前置知识
x
≡
y
(
m
o
d
p
)
x\equiv y\pmod p
x≡y(modp) 表示
x
%
p
=
y
%
p
x\%p=y\%p
x%p=y%p。
如果
a
⋅
a
′
≡
1
(
m
o
d
p
)
a·a'\equiv1 \pmod p
a⋅a′≡1(modp),那么
a
′
a'
a′ 称为
a
a
a 在模
p
p
p 意义下的乘法逆元。如果
p
p
p 是素数,可以用费马小定理+快速幂,结论:
a
′
=
a
p
−
2
(
m
o
d
p
)
a'=a^{p-2}\pmod p
a′=ap−2(modp)。(如果想学的话可以看其他大佬的文章)但是如果
p
p
p 不是素数,或者时间复杂度不允许有
log
\log
log 怎么办?
递推式推导
令
A
=
⌊
p
x
⌋
A=\lfloor \frac{p}{x} \rfloor
A=⌊xp⌋,
B
=
p
%
x
B=p\%x
B=p%x。
p
=
A
⋅
x
+
B
→
A
⋅
x
+
B
≡
0
(
m
o
d
p
)
→
A
⋅
x
≡
−
B
(
m
o
d
p
)
p=A·x+B \rightarrow A·x+B\equiv0\pmod p\rightarrow A·x\equiv-B\pmod p
p=A⋅x+B→A⋅x+B≡0(modp)→A⋅x≡−B(modp)
设
i
n
v
[
i
]
inv[i]
inv[i] 表示
i
i
i 在模
p
p
p 意义下的乘法逆元。
A
⋅
x
⋅
i
n
v
[
x
]
⋅
i
n
v
[
B
]
≡
−
B
⋅
i
n
v
[
x
]
⋅
i
n
v
[
B
]
(
m
o
d
p
)
A·x·inv[x]·inv[B]\equiv-B·inv[x]·inv[B]\pmod p
A⋅x⋅inv[x]⋅inv[B]≡−B⋅inv[x]⋅inv[B](modp)
由乘法逆元的定义可得:
A
⋅
i
n
v
[
B
]
≡
−
i
n
v
[
x
]
(
m
o
d
p
)
A·inv[B]\equiv-inv[x]\pmod p
A⋅inv[B]≡−inv[x](modp)
把
A
A
A 和
B
B
B 代入:
⌊
p
x
⌋
⋅
i
n
v
[
p
%
x
]
≡
−
i
n
v
[
x
]
(
m
o
d
p
)
→
i
n
v
[
x
]
=
(
−
⌊
p
x
⌋
⋅
i
n
v
[
p
%
x
]
%
p
+
p
)
%
p
\lfloor \frac{p}{x} \rfloor·inv[p\%x]\equiv-inv[x]\pmod p\rightarrow inv[x]=(-\lfloor \frac{p}{x} \rfloor·inv[p\%x]\%p+p)\%p
⌊xp⌋⋅inv[p%x]≡−inv[x](modp)→inv[x]=(−⌊xp⌋⋅inv[p%x]%p+p)%p(化为非负数)
由于
p
%
x
<
x
p\%x<x
p%x<x,
p
>
x
且
p
%
x
≠
0
p>x\text{且} p\%x\neq 0
p>x且p%x=0(如果要算一个
≥
p
\ge p
≥p 的
x
x
x 的逆元,答案为
x
%
p
x\%p
x%p 的逆元),所以该递推式成立。
代码
#include<bits/stdc++.h>
using namespace std;
#define p 998244353
#define N 10000000
long long inv[N];
void find_inv(){
inv[1]=1;
for(int i=2;i<=N;i++)
inv[i]=(-p/i*inv[p%i]%p+p)%p;
}
int main(){
find_inv();
for(int i=1;i<=N;i++) printf("%lld ",inv[i]);
printf("\n");
return 0;
}