浅谈乘法逆元的线性算法
众所周知,乘法逆元可以通过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 }
2.阶乘逆元的线性递推
我们先用Exgcd求出一个阶乘值的逆元
之后,我们就能轻松用递推求出阶乘的逆元了。