求 1..n 之间每个数的逆元,如果都用费马小定理或者扩展欧几里得算,那么复杂度将会达到 $O(n log p)$ 。利用一些递推式,可以线性地求出1..n中每个数的逆元,从而复杂度可以减少一个log。常用的一个递推公式是
$$i^{-1} = -leftlfloor frac{p}{i} ight floor cdot (p mod i)^{-1} mod p$$
这一公式的正确性也很好证明,等式右端可以写成(模p意义下)
$$-frac{leftlfloor frac{p}{i} ight floor}{p-leftlfloor frac{p}{i} ight floor 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不改变结果 }