ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

预处理阶乘与阶乘逆元

2026/8/10 20:07:15 拓冰建站 浏览量
预处理阶乘与阶乘逆元

[适用范围]

​ 在某些需要多次计算组合数 \(C^{m}_{n}\) 或排列数 \(A^{m}_{n}\) 并要求将答案对一个大质数取模(如 \(998244353\))的题目中,每次暴力地计算显然会超时。根据排列数与组合数的定义,就需要预处理出阶乘以及阶乘的逆元来优化。

[具体思路]

​ 阶乘很好预处理,设 \(fac_i = i!\) ,则有下式:

\[fac_i = \begin{cases}1 & \text{ if } x = 0 \\fac_{i - 1} \times i & \text{ if } x \ge 1 \end{cases} \]

​ 递推即可。

​ 设 \(inv_i\)\(fac_i\) 模质数 \(p\) 的逆元,发现不容易正推,考虑倒推求解。

​ 先使用费马小定理和快速幂将 \(inv_n\) 的值算出来,有:

\[inv_n = (fac_n)^{-1} \equiv fac_n^{p - 2} (\bmod p) \]

​ 再倒推:

\[inv_i \equiv inv_{i + 1} \times (i + 1) (\bmod p) \]

​ 然后就处理完了。

code

#define ll long longll fpow(ll x, ll y) {ll res = 1, t = x;while(y) {if(y & 1) res = (res * t) % MOD;t = (t * t) % MOD;y >>= 1;}return res;
}ll fac[N + 10], inv[N + 10];void init() {fac[0] = 1;for(int i = 1; i <= n; i++) fac[i] = (fac[i - 1] * i) % MOD;inv[n] = fpow(fac[n], MOD - 2);for(int i = n - 1; i >= 0; i--) inv[i] = (inv[i + 1] * (i + 1)) % MOD;
}