浅谈乘法逆元的线性算法

众所周知,乘法逆元可以通过Exgcd和费马小定理求解,如果我们在题目中需要预处理连续的一段数的逆元,我们需要更高效的算法求解。

1.线性递推求解乘法逆元

首先,我们声明在下列计算中同余均是在模p意义下

我们可以简单计算1-1≡1

考虑任意正整数i,假定i-1的逆元已经正确计算,我们递推方程的计算过程如下:

令$p=k*i+r$,则$k=\lfloor\frac{p}{i}\rfloor,r=p\ mod\ i$
$$k*i+r\equiv0\pmod p$$
$$k*r^{-1}+i^{-1}\equiv0\pmod p$$
$$i^{-1}\equiv-k*r^{-1}\pmod p$$
$$i^{-1}\equiv-\lfloor\frac{p}{i}\rfloor*(p\ mod\ i)^{-1} \pmod p$$
$$i^{-1}\equiv p-\lfloor\frac{p}{i}\rfloor*(p\ mod\ i)^{-1} \pmod p$$

注意:最后一步我们在等号右边加p,目的是防止出现负数。由于p mod p =0 所以我们在右边加p是正确的

综上,我们得到了线性递推乘法逆元的算法。时间复杂度为O(n)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int n, a[3000010], p;
 5 int main() {
 6     scanf("%d%d", &n, &p);
 7     a[1] = 1;
 8     for(register int i = 2; i <= n; ++i)
 9         a[i] =(ll) (p - p / i) * a[p % i] % p;
10     for(register int i = 1; i <= n; ++i) printf("%d\n", a[i]);
11     return 0;
12 }
View Code

2.阶乘逆元的线性递推

我们先用Exgcd求出一个阶乘值的逆元

之后,我们就能轻松用递推求出阶乘的逆元了。

posted @ 2019-06-26 17:29  AD_shl  阅读(747)  评论(0编辑  收藏  举报