网上的求逆方法普遍长这样
a[1]=1;
for(int i=2;i<=n;++i) a[i]=(mod-(mod/i))%mod*a[mod%i]%mod;
下面介绍一种简单且万能的
pr[1]=1;
for(int i=2;i<=n;++i) pr[i]=pr[i-1]i%mod;
b[n]=qpow(pr[n],mod-2);
for(int i=n-1;i;–i) b[i]=b[i+1](i+1)%mod;
b[1]=1;
for(int i=2;i<=n;++i) b[i]=b[i]*pr[i-1]%mod;
讲解开始
逆元的定义
在 ( m o d p ) \pmod p (modp)意义下, i × i − 1 ≡ 1 i\times i^{-1}\equiv1 i×i−1≡1,则 i i i与 i − 1 i^{-1} i−1互为逆元
使用逆元的意义:为了保证精度,维护整数问题(即数论问题)的过程中,不能除,于是利用与原数积在模意义下为1
的数,来替代除法
a n = n a_n=n an=n的逆元求法
常用,但是常数有点大
推导:
模
p
意
义
下
,
求
i
的
逆
元
p
=
k
i
+
r
(
k
=
⌊
p
i
⌋
,
r
=
p
m
o
d
i
)
k
i
+
r
≡
0
(
m
o
d
p
)
i
−
1
r
−
1
(
k
i
+
r
)
≡
0
(
m
o
d
p
)
i
−
1
+
k
r
−
1
≡
0
(
m
o
d
p
)
i
−
1
≡
−
k
r
−
1
(
m
o
d
p
)
由
于
r
=
p
m
o
d
i
,
则
r
<
i
,
求
i
时
r
已
求
出
,
可
以
递
归
求
解
边
界
1
−
1
=
1
\begin{aligned} &模p意义下,求i的逆元\\ &p=ki+r\quad(k=\lfloor\frac{p}{i}\rfloor,r=p\bmod i)\\ &ki+r\equiv 0\pmod p\\ &i^{-1}r^{-1}(ki+r)\equiv 0\pmod p\\ &i^{-1}+kr^{-1}\equiv 0\pmod p\\ &i^{-1}\equiv -kr^{-1}\pmod p\\ &由于r=p\bmod i,则r<i,求i时r已求出,可以递归求解\\ &边界1^{-1}=1 \end{aligned}
模p意义下,求i的逆元p=ki+r(k=⌊ip⌋,r=pmodi)ki+r≡0(modp)i−1r−1(ki+r)≡0(modp)i−1+kr−1≡0(modp)i−1≡−kr−1(modp)由于r=pmodi,则r<i,求i时r已求出,可以递归求解边界1−1=1
Code
a[1]=1;
for(int i=2;i<=n;++i) a[i]=(mod-(mod/i))%mod*a[mod%i]%mod;
任意数列的逆元求法
常数又小,适用范围又广
不学他学谁?
推导
对
于
{
a
n
}
(
通
常
是
a
n
=
n
的
数
列
)
,
记
p
r
i
=
∏
j
=
1
i
a
j
,
第
一
遍
,
i
n
v
n
=
p
r
n
p
−
2
(
即
p
r
n
的
逆
元
)
≡
1
∏
i
=
1
n
a
i
i
n
v
i
=
i
n
v
i
+
1
×
a
i
+
1
,
递
推
下
去
第
二
遍
,
i
n
v
i
=
i
n
v
i
×
p
r
i
−
1
时
间
复
杂
度
O
(
N
)
\begin{aligned} &对于\{a_n\}(通常是a_n=n的数列),记pr_i=\prod_{j=1}^ia_j,\\ &第一遍,inv_n=pr_n^{p-2}(即pr_n的逆元)\equiv\frac{1}{\prod_{i=1}^na_i}\\ &inv_i=inv_{i+1}\times a_{i+1},递推下去\\ &第二遍,inv_i=inv_i\times pr_{i-1} \\\\&时间复杂度O(N) \end{aligned}
对于{an}(通常是an=n的数列),记pri=j=1∏iaj,第一遍,invn=prnp−2(即prn的逆元)≡∏i=1nai1invi=invi+1×ai+1,递推下去第二遍,invi=invi×pri−1时间复杂度O(N)
Code
pr[1]=1;
for(int i=2;i<=n;++i) pr[i]=pr[i-1]*i%mod;
b[n]=qpow(pr[n],mod-2);
for(int i=n-1;i;--i) b[i]=b[i+1]*(i+1)%mod;
b[1]=1;
for(int i=2;i<=n;++i) b[i]=b[i]*pr[i-1]%mod;
Tips
- 注意边界:
法一中inv[1]
要赋初值
法二中最后一层循环由于pr[0]=0
,无法更新inv[1]
,那么手动赋1
- 注意求逆元的范围
想清楚就行了