若存在整数 x 使得 ax≡1(modm),则称 x 是 a 模 m 的乘法逆元,记作 a−1 或 a∗−1。
存在条件:a−1 存在 ⟺gcd(a,m)=1。
当 m=p 为素数且 a≡0 时,逆元一定存在。
3.2 费马小定理
若 p 为素数且 gcd(a,p)=1,则 ap−1≡1(modp)。
等式两边乘 a−1:
ap−2≡a−1(modp)
所以模素数 p 下,a 的逆元就是 ap−2(modp)——直接用快速幂算。
long long inv(long long a, long long p) { return qpow(a, p - 2, p); // 快速幂}
3.3 为什么逆元 = 模意义下的除法?
因为 b/a≡b⋅a−1(modm)。
验证:b⋅a−1⋅a≡b⋅1≡b(modm)。乘上去、再除回来,确实还原了。
四、模意义下的组合计数
4.1 阶乘与逆阶乘
要算大量的 (kn),预处理阶乘和逆阶乘:
(kn)=k!⋅(n−k)!n!≡n!⋅(k!)−1⋅((n−k)!)−1(modp)
预处理方式:
const int MOD = 998244353;const int MAXN = 3000006;long long fact[MAXN], inv_fact[MAXN];void init(int n) { fact[0] = 1; for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % MOD; // 只需一次快速幂算 (n!)^{-1},然后倒推 inv_fact[n] = qpow(fact[n], MOD - 2, MOD); for (int i = n - 1; i >= 0; i--) inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;}long long C(int n, int k) { if (k < 0 || k > n) return 0; return fact[n] * inv_fact[k] % MOD * inv_fact[n - k] % MOD;}
关键点:逆阶乘不需要逐个算快速幂,从 inv_fact[n] 倒推只需 O(n),因为:
(k!)−1=((k+1)!)−1⋅(k+1)
4.2 插一句:Vandermonde 恒等式
后面会用到的一个重要组合恒等式:
j∑(j+ra)(jb)=(b+ra+b)
它是范德蒙德卷积 ∑j(ja)(n−jb)=(na+b) 的变形。本质上说的是:从 A∪B(∣A∣=a,∣B∣=b)中选 b+r 个元素,按”从 A 中选多少”来分类求和,结果等于直接选。
#include <cstdio>#include <algorithm>using namespace std;const int MOD = 998244353;const int MAXN = 3000006;long long fact[MAXN], inv_fact[MAXN];long long qpow(long long a, long long b, long long mod) { long long res = 1; a %= mod; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res;}void init(int n) { fact[0] = 1; for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % MOD; inv_fact[n] = qpow(fact[n], MOD - 2, MOD); for (int i = n - 1; i >= 0; i--) inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;}long long C(int n, int k) { if (k < 0 || k > n) return 0; return fact[n] * inv_fact[k] % MOD * inv_fact[n - k] % MOD;}int main() { int X1, X2, X3; scanf("%d%d%d", &X1, &X2, &X3); init(X1 + X2 + X3); long long ans = 0; int M = min(X1, X2 + 1); for (int s = 1; s <= M; s++) { long long term = C(X2 + 1, s) * C(X1 - 1, s - 1) % MOD; term = term * C(X2 + X3 - s, X3) % MOD; ans = (ans + term) % MOD; } printf("%lld\n", ans); return 0;}