排列组合大复习
0x00 前言
初赛考试的重点,非常重要!!!(标 ☆ 的除外)
0x01 加法原理与乘法原理 ★★★★
加法原理:对于一件事,若其可以分为 \(n\) 种方法,第 \(i\) 种方法的方案数为 \(a_i\),则总方案数为 \(\sum_{i=1}^n a_i\)。
乘法原理:对于一件事,若其可以分为 \(n\) 个步骤,第 \(i\) 个步骤的方案数为 \(a_i\),则总方案数为 \(\prod_{i=1}^n a_i\)。
0x02 排列数、组合数的定义及性质 ★★★★★
一、定义
排列数:排列,顾名思义是有顺序的。所谓从 \(n\) 个不同元素中取出 \(m\) 个元素的排列数,即从 \(n\) 个元素中取出 \(m\) 个元素形成一个有序的序列,可形成的不同序列的数量,记为 \(A_n^m\)(有些古老的资料上写作 \(P_n^m\))(\(m<n\) 且 \(m,n\in\N_+\)),其中这 \(m\) 个元素是有顺序的,如 \(1,2,3\) 与 \(1,3,2\) 是两个不同的排列。
全排列:特殊地,当 \(n=m\) 时,即从 \(n\) 个不同元素中取出 \(n\) 个元素的排列数,称作全排列。
组合数:组合,强调“组”之后的“合”,是一个没有顺序的整体。所谓从 \(n\) 个不同元素中取出 \(m\) 个元素的组合数,即从 \(n\) 个不同元素中取出 \(m\) 个元素形成一个集合,可形成的不同集合的数量,记为 \(C_n^m\)(也写为 \(\tbinom{n}{m}\),两者上下相反!!!)。选出的这些元素是无序的,如 \(1,2,3\) 和 \(1,3,2\) 应被算为同一种选法。
二、计算公式
公式 1(排列数定义式):\(A_n^m=n\times(n-1)\times\dots\times(n-m+1)=\dfrac{n!}{(n-m)!}\ (n,m\in\N_+,0<m\le n)\),即以 \(n\) 为结尾的连续 \(m\) 个正整数相乘。
证明:选取过程中,可以把 \(1\) 次取出 \(m\) 个元素看成 \(m\) 次取出 \(1\) 个元素,第一次取出有 \(n\) 种;而第二次取时,第一次已经取出 \(1\) 个,只剩下了 \((n-1)\) 个,所以有 \(n-1\) 种……当第 \(i\) 次取时,前面 \(i-1\) 次已经取了 \(i-1\) 个,还剩 \(n-i+1\) 个。由于是分步操作,由乘法原理可得总方案数为 \(\prod_{i=1}^m(n-i+1)\),即为上面的式子。
公式 2:\(A_n^n=\dfrac{n!}{0!}=n!\ (n\in\N_+)\)
公式 3(组合数定义式):\(C_n^m=\tbinom{n}{m}=\dfrac{A_n^m}{A_m^m}=\dfrac{n!}{m!\cdot(n-m)!}\ (n,m\in\N_+,0<m\le n)\),即排列数除以 \(m\) 的全排列。
证明:对于从 \(n\) 个不同元素中选出 \(m\) 个元素的组合数,可以看成把从 \(n\) 个不同元素中选出 \(m\) 个元素的排列数中所有对组合数而言的相同选法合并(有点绕 T_T)。而一个 \(m\) 个元素的组合总共有 \(A_m^m\) 个对应的排列(为什么?),即 \(C_n^m\times A_m^m=A_n^m\),即得 \(C_n^m=\dfrac{A_n^m}{A_m^m}\)。
为什么?:由于组合是没有顺序的,要把它转换为有顺序的排列,可以看成从这 \(m\) 个元素中有序取出 \(m\) 个元素形成一个排列,那么总共就有 \(A_m^m\) 个排列了。
公式 4(规定):特别地,规定当 \(m>n\) 时,\(A_n^m=C_n^m=0\);当 \(m=0\) 时,\(A_n^m=C_n^m=1\)(即不选)。
公式 5:对于 \(\forall m,n\in\Z\) 满足 \(0\le m\le n\),有 \(C_n^m=C_n^{n-m}\)。
证明 1:从式子的含义考虑。\(C_n^m\) 表示从 \(n\) 个元素中无序选出 \(m\) 个元素,那么自然也可以看成从 \(n\) 个元素中找出 \(n-m\) 个元素不选,所以 \(C_n^m=C_n^{n-m}\)。
证明 2:\(C_n^m=\dfrac{n!}{m!\cdot(n-m)!}=\dfrac{n!}{(n-m)!\cdot m!}=C_n^{n-m}\)
公式 6(杨辉三角原理):\(C_n^m=C_{n-1}^{m-1}+C_{n-1}^m\)
证明 1:对于 \(C_n^m\),考虑当前第 \(n\) 个元素取不取。若取,则在前面 \(n-1\) 个元素中应取 \(m-1\) 个,即为 \(C_{n-1}^{m-1}\);若不取,则须在前 \(n-1\) 个元素中取 \(m\) 个,即为 \(C_{n-1}^m\),由加法原理二者相加即可。
证明 2:
三、排列数、组合数求解方法
直接用定义式。先求出 \(m!,(n-m)!\) 的逆元,时间复杂度各为 \(O(m),O(n-m)\);再求出 \(n!\bmod p\) 的值,时间复杂度 \(O(n)\)。最后全部代入即可,时间复杂度 \(O(n)\)。
int inv[N];
int facinv(int n,int p){ // 求 n! 逆元
inv[1]=1;
for (int i=2;i<=n;++i) inv[i]=p-(p/i)*1ll*inv[p%i]%p;
int res=1;
for (int i=1;i<=n;++i) res=res*1ll*inv[i]%mod;
return res;
}
int fac(int n,int p){
int res=1;
for (int i=2;i<=n;++i) res=res*1ll*i%p;
return res;
}
int A(int n,int m,int p){ return fac(n)*1ll*facinv() }
0x03 插板法 ★★★★★
一、Task 1:基础
题目:求 \(x_1+x_2+\dots+x_k=n\ (k,n\in\N_+)\) 的正整数解个数。
等价问法:求把 \(n\) 个元素分为 \(k\) 个非空组的方案数。
解法(按等价问法考虑):要把 \(n\) 个元素分为 \(k\) 个非空组,可以看成在这些元素的 \(n-1\) 个空隙中插入 \(k-1\) 块板(不可在一个空隙中插多块),从而将元素分为 \(k\) 个非空组,总方案数即为 \(C_{n-1}^{k-1}\)。
二、Task 2:变形 1
题目:求 \(x_1+x_2+\dots+x_k=n\ (k,n\in\N_+,k\le n)\) 的非负整数解个数。
等价问法 1:求把 \(n\) 个元素分为不多于 \(k\) 个非空组的方案数。
等价问法 2:求把 \(n\) 个元素分为 \(k\) 组(可为空)的方案数。
解法(按题目本身考虑):考虑化归。现在 \(x_1,x_2,\dots,x_k\ge 0\),而前面我们解决了其均大于 \(0\) 的情况,所以我们只需要将大于等于 \(0\) 转变为大于 \(0\) 即可,发现给每个元素加 \(1\) 即可。从而,题目变为求 \(y_1+y_2+\dots+y_k=n+k\ (k,n\in\N_+,k\le n)\) 的正整数解个数,其中 \(y_i=x_i+1\ (1\le i\le n)\)。由 Task 1 可求得解为 \(C_{n+k-1}^{k-1}\),而每一个 \(y_i\) 对应唯一的一个 \(x_i\),所以最终总方案数为 \(C_{n+k-1}^{k-1}\)。
三、Task 3:变形 2
题目:求 \(x_1+x_2+\dots+x_k=n\ (k,n\in\N_+,k\le n)\) 满足 \(\forall i\in[1,n]\cap\Z,x_i>a_i\ (a_i\in\N_+)\) 的解的个数。
解法:依旧化归。现在要求解大于 \(a_i\),考虑往前面的“与 \(0\) 比”上面靠。令 \(y_i=x_i-a_i\ (1\le i\le n)\),由 \(x_i>a_i\) 得 \(y_i\in\N_+\),则有 \(y_1+y_2+\dots+y_k=n-\sum a_i\)。由 Task 1 可知答案为 \(C_{n-\sum_{i=1}^k a_i}^{k-1}\)。
四、总结
插板法特别适用于一些求 \(\sum x_i=n\) 满足 \(x_i>a_i\) 的整数解问题。对于一些分组、取不相邻元素的题目,也可以考虑通过设各组元素数量、组/元素间元素数量等转变为不定方程整数解个数问题。总之,插板法注重题目与不定方程的转换,解题时注意插板、设元即可。
0x04 牛顿二项式定理 ☆
内容:\((a+b)^n=C_n^0 a^nb^0+C_n^1 a^{n-1}b^1+\dots+C_n^n a^0b^n=\sum_{i=1}^n C_n^i a^{n-i}b^i=\sum_{i=1}^n C_n^i a^ib^{n-i}\)。
证明:考虑展开后一个项是如何产生的。对于其中一项 \(a^xb^{n-x}\),其需要在 \(n\) 个括号中有 \(x\) 个出 \(a\),剩下 \(n-x\) 个出 \(b\) 相乘产生,故共有 \(C_n^x\) 个。
0x05 多重集上的排列、组合 ☆
前置知识:插板法
一、多重集的定义
何为多重集?多重集指一个包含重复元素的广义集合(即不含有互异性的数组),一般用 \(S=\{n_1\cdot a_1,n_2\cdot a_2,\dots,n_k\cdot a_k\}\) 表示由 \(n_1\) 个 \(a_1\),\(n_2\) 个 \(a_2\)……\(n_k\) 个 \(a_k\) 构成的共 \(\sum n_k\) 个元素的多重集。
二、多重集的排列数/多重组合数
定义:多重集的排列数,也称多重组合数、多重集的全排列数,多重集 \(S\) 的排列数可用 \(\tbinom{n}{n_1,n_2,\dots,n_k}\) 表示,其中 \(n=\sum n_i\)。具体地,多重集的排列数指将多重集中所有元素取出排列成一个有序数列,可排出的不同数列有几种。
解法:求解该问题,我们注意到值不同的元素是不一样的,而值相同的元素是一样的。考虑逆向思维,将多重集的排列数变为整个多重集中所有元素的全排列(每个元素都不一样),只需要乘上每种元素内部的全排列即可。即 \(\tbinom{n}{n_1,n_2,\dots,n_k}\times\prod_{i=1}^k n_i!=n!\),所以移项得到多重组合数的计算公式:\(\tbinom{n}{n_1,n_2,\dots,n_k}=\dfrac{n!}{\prod_{i=1}^k n!}\)。
三、多重集的组合数
定义:多重集的组合数,即重多重集中任选 \(m\ (m<\min n_i)\) 个元素可构成的不同多重集的数量。
解法:设值为 \(a_i\) 的元素被选 \(x_i\) 个,则有 \(x_1+x_2+\dots+x_k=m\),题目即转换为求该不定方程的非负整数解,由插板法可得答案为 \(C_{m+k-1}^{k-1}\)。
0x06 错位排列 ★
考虑这样一个问题。现在有一个各元素互不相同的数列 \(a_i\ (1\le i\le n)\),求满足 \(\forall i\in[1,n]\cap\Z,a_{p_i}\ne a_i\) 的 \(1\sim n\) 的排列 \(p_i\) 的个数。
采用动态规划。记 \(f_n\) 表示 \(n\) 规模下的答案。要求 \(n\) 时的答案,则考虑与更小规模答案的联系。假设现在 \(p_i=i\),为了让 \(p_i\ne i\),显然要将 \(p_i\) 与某一个 \(p_j\) 交换。如果前 \(n-1\) 个都满足条件,只需要随便选一个 \(1\le j\le n-1\) 交换即可,故该方案有 \((n-1)f_{n-1}\) 个。但是,如果前 \(n-1\) 个中正好有且仅有一个 \(j\) 满足 \(p_j=j\),那么交换 \(p_i,p_j\) 也满足条件,此时由于 \(j\) 可取 \(1\sim n-1\),故共有 \((n-1)f_{n-2}\) 种方案。综上,总方案数为 \(f_n=(n-1)(f_{n-1}+f_{n-2})\),其中边界条件为 \(f_1=0,f_2=1\),时空复杂度均为 \(O(n)\)。
0x07 圆排列 ☆
对于圆排列 \(Q_n^m\),表示从 \(n\) 个元素互不相同的数列中选出 \(m\) 个元素组成一个圆,可组成的圆的数量。考虑化环为链,在某处拆开该圆,形成一个环,则由于圆上共有 \(m\) 个空隙,所以共有 \(m\) 种方案。拆开后的所有方案综合起来即为从 \(n\) 个元素中有序选出 \(m\) 个元素的所有方案,故有 \(n\times Q_n^m=A_n^m\),得 \(Q_n^m=\dfrac{A_n^m}{m}\)。
0x08 卡特兰(Catalan)数 ★★★☆
一、何为卡特兰数?
卡特兰数,因比利时数学家 Eugène Charles Catalan 在 1958 年研究括号序列计数问题时发现了这一数列而得名,但其实清朝数学家明安图在 18 世纪 30 年代就已发现该数列。(所以为什么不叫明安图数?)
具体地,卡特兰数满足 \(C_n=\begin{cases}1&,n=0\\ \sum_{i=0}^{n-1}C_iC_{n-i-1}&,n>0\end{cases}\),数列前几项为 \(C_0=1,C_1=1,C_2=2,C_3=5,C_4=14,C_5=42,\dots\)。
二、适用场景
I. Task 1:路径计数问题
题目:现有一个 \(n\times n\) 大小的网格,要求从网格的左下角走到右上角,但只可向右或向上走,且不得经过 \(y>x\) 范围内的任何格点。如下图所示。

一般来说,直接用头顶标数法即可。然而这里我们换一种方式考虑。我们令规模为 \(n\) 的问题答案为 \(f_n\)。考虑最后一次经过的 \(y=x\) 上的点(不算终点)的坐标 \((m,m)\),那么可将路径分为两部分,即 \((0,0)\to(m,m),(m,m)\to(m+1,m)\to(n,n-1)\to(n,n)\),其中前一部分共有 \(f_m\) 种方案,后一部分中前后两段走法唯一,只需考虑 \((m+1,m)\to(n,n-1)\),共 \(f_{n-m-1}\) 种方案,由乘法原理可得总方案为 \(f_mf_{n-m-1}\)。由于 \(m\in[0,n-1]\cap\Z\),所以最终方案数等于 \(\sum_{i=0}^{n-1}f_if_{n-i-1}\),其中 \(f_0=1\)。观察可得恰为卡特兰数的表示形式。
II. Task 2:建模
将该问题建立数学模型。注意到不越过 \(y=x\) 即为向右走的次数大于等于向上走的次数。记向右走为 \(+1\),向上走为 \(-1\),每次走的方向为 \(a_i\),共有 \(n\) 个 \(+1\) 与 \(n\) 个 \(-1\)。则题目变转变为满足任意子序列元素和均非负的合法序列个数,答案也应为 \(C_n\)。
III. Task 3:二叉树计数问题
题目:求含有 \(n\) 个结点的形态不同的二叉树的数目。
对于该问题,肯定要将大问题转换为两个小问题。观察到二叉树最多只有两个子树,很适合划分问题。依旧设规模为 \(n\) 的问题答案为 \(f_n\)。则当左子树有 \(i\) 个结点时,右子树有 \(n-i-1\) 个结点,可得 \(f_n=f_if_{n-i-1}\)。故最终答案为 \(\sum_{i=0}^{n-1}f_if_{n-i-1}\),其中 \(f_0=f_1=1\),符合卡特兰数规律。
IV. Task 4:括号匹配问题/找零问题/出栈序列计数问题
核心要点:这类题目往往都可以转换为某一物品(如左括号、零钱、栈内元素个数)的 \(\pm\, 1\) 操作,只需划归为 Task 1,即设 \(+1\) 为向右,\(-1\) 为向上进行标数法即可。
标数法:具体地,即在每个网格之间标上数,每个数等于它左侧和下侧两数之和(因为是向上、向右走)。
三、计算公式
公式 1:\(C_n=\dfrac{1}{n+1}\tbinom{2n}{n}=\dfrac{(2n)!}{n!(n+1)!}\)。
公式 2:\(C_n=\tbinom{2n}{n}-\tbinom{2n}{n+1}\)。
公式 3:\(C_n=\dfrac{4n-2}{n+1}C_{n-1}\)。
证明:略,见 OI-WIKI。
四、总结
卡特兰数的题目,一般是用其它方法做不出来的,所以可以在排列组合题想不出来时看到整道题以一个量不断进行 \(\pm\, 1\) 操作且时刻大于等于 \(0\) 命题时,考虑尝试定义向右、向上用标数法解决。
0x09 容斥原理 ★★
内容:对于 \(n\) 个集合 \(S_1,S_2,\dots,S_n\),有 \(\big|\bigcup_{i=1}^n S_i\big|=\sum_{i=1}^n \Big[(-1)^{n-1}\sum_{j=1}^{n-i+1}\big|\bigcap_{k=j}^{i+j-1} S_k\big|\Big]\),其中 \(\big|S\big|\) 表示集合 \(S\) 中元素的个数。
证明:画韦恩图即可。标上每一小块被计算的个数并时刻更新。
0x0A 鸽巢原理 ★★
内容:把 \(n\) 个元素分成 \(k\) 组,则必有一组存在不少于 \(\big\lceil\dfrac{n}{k}\big\rceil\) 个元素。
证明:采用反证法。假设每组元素均少于 \(\big\lceil\dfrac{n}{k}\big\rceil\) 个,则元素总个数必小于等于 \(k(\big\lceil\dfrac{n}{k}\big\rceil-1)<k\times\dfrac{n}{k}=n\),矛盾,舍去。


浙公网安备 33010602011771号