组合数学总结

数学是毒瘤


组合数学总结。

如果说数论是数学的基础,那么组合数学往后就是高阶了。这之后的数学不再像数论那么板子,而是变得需要更多的推理和组合了。知识很简单,难的是应用。

本来还有什么容斥原理,看不懂,于是没放


初始化

为了方便快速求排列组合,我们需提前预处理阶乘和阶乘的乘法逆元。

\(\mathit{fac}[i]\) 表示 \(i\) 的阶乘,\(\mathit{inv}[i]\) 表示 \(\boldsymbol i\) 的阶乘 的乘法逆元。

\(\mathit{inv}[i]\)\(\boldsymbol i\) 的阶乘 的乘法逆元,不是 \(i\) 的乘法逆元!

2024/3/17 upd.

注意:若 \(\boldsymbol n\) 的规模超过 \(\boldsymbol{10^6}\) 级别,请勿预处理 \(\boldsymbol{inv[i]}\),而是即时计算!

注意:若 \(\boldsymbol n\) 的规模超过 \(\boldsymbol{10^7}\) 级别,请线性求逆元!公式:\(\boldsymbol{inv[i]=inv[i+1]\times(i+1)~\mathbf{mod~MOD}}\)。——2024/5/19 upd.

void init() {
	fac[0] = inv[0] = 1;
	for (int i = 1; i < MAXN; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = power(fac[i], MOD - 2, MOD);
	}
}

一般情况下,数论题都有一个 \(\mathrm{MOD}\) 值,否则可以传参 \(p\) 表示模数。

排列数 \(\boldsymbol{\mathbf A_n^m}\)

排列数的计算公式如下:

\[\mathrm A_n^m=\frac{n!}{(n-m)!} \]

inline int A(int n, int m, int p) {
	if (n < m) return 0;
	return fac[n] * inv[n - m] % p;
}

组合数 \(\boldsymbol{\binom nm}\)

组合数的计算公式如下:

\[\binom nm=\frac{n!}{m!(n-m)!} \]

inline int C(int n, int m, int p) {
	if (n < m) return 0;
	return fac[n] * inv[m] % p * inv[n - m] % p;
}

排列数和组合数都只需 \(O(n)\) 的预处理便可 \(O(1)\) 查询。

若需要即时求组合数,可以根据公式直接记忆化搜索:

int C(int n, int m) {
	if (m == 0 || m == n) return 1;
	if (cc[n][m] != 0) return cc[n][m];
	return cc[n][m] = C(n - 1, m) + C(n - 1, m - 1);
}

二项式定理

\[(a+b)^n=\sum_{k=0}^n\binom nka^{n-k}b^k \]

组合数性质

\[\binom{n}{m}=\binom{n}{n-m}\tag{1} \]

相当于将选出的集合对全集取补集,故数值不变。(对称性)

\[\binom{n}{k} = \frac{n}{k} \binom{n-1}{k-1}\tag{2} \]

由定义导出的递推式。

\[\binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1}\tag{3} \]

组合数的递推式(杨辉三角的公式表达)。我们可以利用这个式子,在 \(O(n^2)\) 的复杂度下推导组合数。

\[\binom{n}{0}+\binom{n}{1}+\cdots+\binom{n}{n}=\sum_{i=0}^n\binom{n}{i}=2^n\tag{4} \]

这是二项式定理的特殊情况。取 \(a=b=1\) 就得到上式。

\[\sum_{i=0}^n(-1)^i\binom{n}{i}=[n=0]\tag{5} \]

二项式定理的另一种特殊情况,可取 \(a=1, b=-1\)。式子的特殊情况是取 \(n=0\) 时答案为 \(1\)

\[\sum_{i=0}^m \binom{n}{i}\binom{m}{m-i} = \binom{m+n}{m}\ \ \ (n \geq m)\tag{6} \]

拆组合数的式子,在处理某些数据结构题时会用到。

\[\sum_{i=0}^n\binom{n}{i}^2=\binom{2n}{n}\tag{7} \]

这是 \((6)\) 的特殊情况,取 \(n=m\) 即可。

\[\sum_{i=0}^ni\binom{n}{i}=n2^{n-1}\tag{8} \]

带权和的一个式子,通过对 \((3)\) 对应的多项式函数求导可以得证。

\[\sum_{i=0}^ni^2\binom{n}{i}=n(n+1)2^{n-2}\tag{9} \]

与上式类似,可以通过对多项式函数求导证明。

\[\sum_{l=0}^n\binom{l}{k} = \binom{n+1}{k+1}\tag{10} \]

通过组合分析一一考虑 \(S={a_1, a_2, \cdots, a_{n+1}}\)\(k+1\) 子集数可以得证,在恒等式证明中比较常用。

\[\binom{n}{r}\binom{r}{k} = \binom{n}{k}\binom{n-k}{r-k}\tag{11} \]

通过定义可以证明。

\[\sum_{i=0}^n\binom{n-i}{i}=F_{n+1}\tag{12} \]

Lucas 定理

\(n,m\) 过大、超出数组的范围时,我们需要用 Lucas 定理求组合数。模数必须为质数。即对于质数 \(p\),有:

\[{n\choose m}\bmod p={n\bmod p\choose m\bmod p}{\left\lfloor n/p \right\rfloor\choose\left\lfloor m/p \right\rfloor}\bmod p \]

易知,\(\dbinom{n\bmod p}{m\bmod p}\)\(n,m\) 范围一定小于等于 \(p\),可以直接求解;\(\dbinom{\lfloor n/p\rfloor}{\lfloor m/p\rfloor}\) 可以继续递归求解。当 \(m=0\) 时,返回 \(1\),递归结束。

int lucas(int n, int m, int p) {
	if (m == 0) return 1;
	return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}

二项式反演

二项式反演用于解决“某个物品恰好若干个”这类计数问题。

直接摆公式。证明需要用到前文提到的组合数定理。

形式 1

\(f_n\) 表示恰好 \(n\) 个的方案数量,\(g_n\) 表示至多 \(n\) 个的方案数量,则:

\[g_n=\sum_{i=0}^n{n\choose i}f_i\iff f_n=\sum_{i=0}^n\left(-1\right)^{n-i}{n\choose i}g_i \]

形式 2

\(f_k\) 表示恰好 \(k\) 个的方案数量,\(g_k\) 表示至少 \(k\) 个的方案数量,则:

\[g_k=\sum_{i=k}^n{i\choose k}f_i\iff f_k=\sum_{i=k}^n\left(-1\right)^{i-k}{i\choose k}g_i \]

错排问题

\[D_n=(n-1)(D_{n-1}+D_{n-2}) \]

posted @ 2024-08-23 16:29  Laoshan_PLUS  阅读(102)  评论(0)    收藏  举报