[适用范围]
在某些需要多次计算组合数 \(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;
}
