组合数学是算法竞赛和面试中计数类问题的理论基础。排列、组合、容斥原理、卡特兰数等工具能优雅地解决"有多少种方案"类问题。
一、排列与组合
Mermaid · 渲染中(下方为源码)
graph LR A[计数] --> B[排列 P] A --> C[组合 C] A --> D[容斥] A --> E[卡特兰数]
公式
P(n, k) = n! / (n-k)! (排列:有序)
C(n, k) = n! / (k!(n-k)!) (组合:无序)
计算(取模)
long MOD = 1_000_000_007;
long[] fact = new long[MAX];
long[] invFact = new long[MAX];
void precompute() {
fact[0] = 1;
for (int i = 1; i < MAX; i++) fact[i] = fact[i-1] * i % MOD;
invFact[MAX-1] = fastPow(fact[MAX-1], MOD-2, MOD);
for (int i = MAX-2; i >= 0; i--) invFact[i] = invFact[i+1] * (i+1) % MOD;
}
long comb(int n, int k) {
if (k < 0 || k > n) return 0;
return fact[n] * invFact[k] % MOD * invFact[n-k] % MOD;
}二、容斥原理
|A ∪ B ∪ C| = |A| + |B| + |C| - |A∩B| - |A∩C| - |B∩C| + |A∩B∩C|