链接:【luogu P3811】
这几天在做 ybtoj 的组合数学,经常要用到乘法逆元,就先去某谷上写了一会乘法逆元。
乘法逆元的定义:若
a
∗
x
≡
1
(
m
o
d
b
)
a*x\equiv1 \pmod {b}
a∗x≡1(modb),且a与b互质,那么我们就能定义: x 为 a 的逆元,记为
a
−
1
a^{-1}
a−1
,所以我们也可以称 x 为
a
在
m
o
d
b
a~~在\bmod b
a 在modb 意义下的倒数。
求解方法:
根据费马小定理,若p 为质数,a 是正整数,且 a,p互质,那么就有:
a
∗
x
≡
a
p
−
1
(
m
o
d
p
)
a*x \equiv a^{p-1} \pmod {p}
a∗x≡ap−1(modp)
x
≡
a
p
−
2
(
m
o
d
p
)
x \equiv a^{p-2} \pmod {p}
x≡ap−2(modp)
使用快速幂即可。
然后现在我们要在线性时间内求出 1~n 的逆元。
首先我们知道
1
−
1
≡
1
(
m
o
d
p
)
1^{-1} \equiv1 \pmod p
1−1≡1(modp)
我们设
p
=
k
∗
i
+
r
p=k*i+r
p=k∗i+r
然后就有
k
∗
i
+
r
≡
0
(
m
o
d
p
)
k*i+r \equiv0 \pmod p
k∗i+r≡0(modp)
左后两边同时乘上
i
−
1
,
r
−
1
i^{-1},r^{-1}
i−1,r−1,有
k
∗
r
−
1
+
i
−
1
≡
0
(
m
o
d
p
)
k*r^{-1}+i^{-1} \equiv0 \pmod p
k∗r−1+i−1≡0(modp)
i
−
1
≡
−
k
∗
r
−
1
(
m
o
d
p
)
i^{-1}\equiv -k*r^{-1}\pmod p
i−1≡−k∗r−1(modp)
将右边两项分别转换,得
i
−
1
≡
−
⌊
p
i
⌋
∗
(
p
m
o
d
i
)
−
1
(
m
o
d
p
)
i^{-1}\equiv -⌊\frac {p}{i}⌋*(p\bmod i)^{-1}\pmod p
i−1≡−⌊ip⌋∗(pmodi)−1(modp)
为了保持其为正数,加上一个 p 使其为正后再取模
最后的式子是
i
−
1
≡
(
p
−
⌊
p
i
⌋
)
∗
(
p
m
o
d
i
)
−
1
(
m
o
d
p
)
i^{-1}\equiv (p-⌊\frac {p}{i}⌋)*(p\bmod i)^{-1}\pmod p
i−1≡(p−⌊ip⌋)∗(pmodi)−1(modp)
然后就可以递推求解了。
直接上代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=3*1e6+10;
ll n,p,inv[V];
int main()
{
scanf("%lld%lld",&n,&p);
inv[1]=1;
printf("%lld\n",inv[1]);
rep(i,2,n)
{
inv[i]=(p-p/i)*inv[p%i]%p;
printf("%lld\n",inv[i]);
}
return 0;
}