求 1..n 之间每个数的逆元,如果都用费马小定理或者扩展欧几里得算,那么复杂度将会达到 $O(n \log p)$ 。利用一些递推式,可以线性地求出1..n中每个数的逆元,从而复杂度可以减少一个log。常用的一个递推公式是
$$i^{-1} = -\left\lfloor \frac{p}{i} \right\rfloor \cdot (p \bmod i)^{-1} \bmod p$$
这一公式的正确性也很好证明,等式右端可以写成(模p意义下)
$$-\frac{\left\lfloor \frac{p}{i} \right\rfloor}{p-\left\lfloor \frac{p}{i} \right\rfloor i} = \frac{1}{i}$$
利用此公式我们可以在 $O(n)$ 时间内求出1..n中每个数的逆元。
void init_inv() { inv[1] = 1; for(int i = 2;i < n;i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod; //加mod不改变结果 }
参考链接:http://aequa.me/index.php/tag/lagrange-interpolation/