第一节 计数原理
加法原理
若完成
A→B 有
x 种方案一,有
y 种方案二,则完成
A→B 的总方案数为
x+y。
要么选
x 种中的一种,有
x 种方案;要么选
y 种中的一种,有
y 种方案。因此总方案数为
x+y 种。同步之间用加法。
乘法原理
若完成
A→B 有
x 种方案,完成
B→C 有
y 种方案,则完成
A→B→C 有
xy 种方案。
对于
A→B 的
x 种方案中的每一种,下一步
B→C 都可选
y 种中的一种,所以总方案数为
xy 种。异步之间用乘法。
排列数
排列数用于解决
n 个相互区分的物品中选出
m 个排成一横排(
区分顺序)的方案数。
考虑
m 个位置的每个位置:第一个位置可放
n 个物品,第二个位置可放
n−1 个物品(已经选出一个,但选出的这一个是哪一个并不重要,因为无论选出的是哪一个,依然还剩
n−1 个物品)……最后一个位置可以放
n−m+1 个物品。
根据上面的加法原理和乘法原理,我们总结出排列数
Anm=n(n−1)⋯(n−m+2)(n−m+1)。若
n<m 或
m<0,
Anm=0。
记
n 的阶乘
n! 为
Ann,特殊地,
0!=1。它一般的意义是
1∼n 的数的排列数。所以组合数
Anm 也可写成
(n−m)!n!。
第二节 组合数
记
Cnm 或
(mn) 为在
n 个物品中选出
m 个物品(
不区分顺序)的方案数。若
n<m 或
m<0,
(mn)=0,否则:
(mn)=m!(n−m)!n!
我们可以用排列数来理解组合数公式。首先从
n 个里选
m 个,区分顺序时为
Anm=(n−m)!n!。然后如果不想区分顺序了,我们需要除以所有
1∼m 的排列,即为
m!。
或是理解为先将
n 个物品排列,取前
m 个,前面
m 个重复了
m! 次,后面还有
n−m 个重复了
(n−m)! 次。
组合数有递推式:
(mn)=(m−1n−1)+(mn−1)
我们可以用数学推导理解:
(m−1n−1)+(mn−1)=(m−1)!(n−m)!(n−1)!+m!(n−m−1)!(n−1)!=m!(n−m)!(n−1)!(m+(n−m))=m!(n−m)!n!=(mn)。
中间一步加法,使用通分的方法进行变形。
也可以用组合意义理解:我们指定其中一个物品,如果选,那么有
(m−1n−1) 种方案(在剩下的
n−1 个选
m−1 个),如果不选,那么有
(mn−1) 种方案(在剩下
n−1 个选
m 个)。
第三节 范德蒙德卷积
∑i=0k(in)(k−im)=(kn+m)
用组合意义可以很轻松地理解这个问题:
n 个红球和
m 个蓝球,在这
n+m 个中选出
k 个。
还有一个很常用的式子:
∑i=0n(in)2=∑i=0n(in)(n−in)=(n2n)
第四节 组合数计算
递推
已证,可用递推式:
(mn)=(m−1n−1)+(mn−1)
解决
n≤5×103 时的组合数计算。时间复杂度
O(n2)。
逆元
在组合数计算时,一般会要求结果对某个数
p(一般是质数)取余数,因为结果实在太大了。
记
x−1 为满足
x⋅x−1≡1(modp) 的数,即为
x 的逆元。则组合数公式变为:
(mn)=n!⋅(m!)−1⋅((n−m)!)−1
所以我们需要预处理阶乘和阶乘的逆元。
Ⅰ 利用线性求逆元
有:
x−1=−⌊xp⌋⋅(pmodx)−1
证明:因为
p=⌊xp⌋⋅x+(pmodx),所以
pmodx≡−⌊xp⌋(modp),得出
x−1=−⌊xp⌋⋅(pmodx)−1。
再利用
(n!)−1=((n−1)!)−1⋅n−1 直接求出阶乘的逆元。
Ⅱ 利用可递推性正反求逆元
有:
(n!)−1=(n+1)−1⋅(n+1)
先预处理阶乘,然后根据费马小定理,直接用快速幂求
(n!)p−2modp 的结果,再反过来递推一遍。
求组合数
利用
(mn)=n!⋅(m!)−1⋅((n−m)!)−1 直接计算即可,注意取模。
一些位置上的递推
我们可能要处理:
∑i=1k(in),∑i=1k(mn+i),∑i=1k(m−1n+i)。分别代表一横行,反斜线和正斜线。
预处理逆元,通过提出阶乘中的一些数,有:
(in)=in−i+1(i−1n)
(mn+i)=n+i−mn+i(mn+i−1)
(m−in+i)=(n−m+2i)(n−m+2i−1)(n+i)(m−i+1)(m−i+1n+i−1)
分别作用于三种。第一种是线性的,后两种需要先用快速幂求出起始位置的组合数。
在组合数计算中,除非必须,我们不建议将所有组合全部拆开。
第五节 组合数的分步计数
分步计数,即为分步骤,分阶段计数。这类问题有可能出现在树上。
定义一种多重组合数
(m1,m2,⋯,mkn),其中
m1+m2+⋯+mk=n。它表示的是分步取走
m1,m2,⋯,mk 个数。
我们可以分步理解,第一步从
n 个数里取走
m1 个,第二步从剩下
n−m1 个取走
m2 个……因此,多重组合数:
(m1,m2,⋯,mkn)=∏i=1k(min−∑j=1i−1mj)
而在分步计数中,我们将多重组合数乘起来,计算不同步的答案。
第六节 容斥原理
对于集合
A1,A2,⋯,An,记集合
S 的大小为
∣S∣,有:
∣⋃i=1nAi∣=∑i∣Ai∣−∑i<j∣Ai∩Aj∣+⋯+(−1)n+1∣⋂i=1nAi∣
证明,可用数学归纳法:
当
n=1 时,
∣A1∣=∣A1∣。
当
n=2 时,
∣A1∪A2∣=∣A1∣+∣A2∣−∣A1∩A2∣。
当
n≥3 时,
∣(A1∪A2∪⋯∪An−1)∪An∣=∣A1∪A2∪⋯∪An−1∣+∣An∣−∣(A1∪A2∪⋯∪An−1)∩An∣。
其中,由
(X∪Y)∩Z=(X∩Z)∪(Y∩Z) 可得
∣(A1∪A2∪⋯∪An−1)∩An∣=∣(A1∩An)∪(A2∩An)∪⋯∪(An−1∩An)∣。
部分情况下,
∣Ai1∩Ai2∩⋯∩Aik∣ 与
i1,i2,⋯,ik 无关,只与
k 有关,记
f(k)=∣⋂i=1kAi∣,则:
∣⋃i=1nAi∣=∑k=1n(kn)f(k)(−1)k+1
下面介绍几种常用的容斥原理应用。
动态规划容斥
在容斥原理中,每一项都有其系数,称其为“容斥系数”。
有时候,
∣Ai1∩Ai2∩⋯∩Aik∣ 有阶段性,可应用动态规划。
状态的设计一般是带容斥系数的状态设计。
树上容斥
树上的容斥大多依赖树形动态规划转移,结合上面讲过的动态规划的容斥和分步计数,解决这类题目。
第七节 斯特林数
第一类斯特林数
定义:将
n 个不同元素划分进
m 个相同的非空
环的方案数,记为
[mn]。
注意环是可以转动且有序的。有:
[mn]=[m−1n−1]+(n−1)[mn−1]
用组合意义解释:前者表示这个元素和其他元素不在一个环,后者表示这个元素和其他元素在一个环。
边界:
[0n]=[n=0]。
第二类斯特林数
定义:将
n 个不同元素划分进
m 个相同的非空集合的方案数,记为
{mn}。
有:
{mn}={m−1n−1}+m{mn−1}
也可用组合意义解释,前者表示这个元素和其他元素不在一个集合,后者表示这个元素和其他元素在一个集合。
边界:
{0n}=[n=0]
或用容斥原理,令集合两两互不相同,集合内元素可被区分,则重复了
m! 次,因此有:
{mn}=m!1∑k=0m(−1)k(km)(m−k)n
划分数
引入一种划分数,表示把非负整数数
n 分成
m 个非负整数的方案数(分出的数不区分顺序),记作
f(n,m)。
钦定
x1≥x2≥x3≥⋯≥xn。基于构造,我们可以想到动态规划中,每一次操作要么在末尾加个
0,要么将前面所有数字增大
1,所以有:
f(n,m)=f(n,m−1)+f(n−m,m)
边界:
f(0,m)=1。
第八节 二项式反演
用于解决一类具有恰好二字的组合计数。
令
f(x) 表示恰好
x 个满足条件的方案数,
g(x) 表示
指定 x 个位置满足条件的方案数,即
g(t)=∑1≤i1≤i2≤⋯≤it≤n∣Ai1∩Ai2∩⋯Ait∣。
可以用
f(t) 表示出
g(t),然后通过二项式反演由
g(t) 表示出
f(t)。
第九节 倍数容斥
倍数容斥用于解决与最大公约数,约数倍数有关的问题。
令
f(x) 表示该数值(指最大公约数,约数或倍数其一)为
x 的方案数,
g(x) 表示该数值为
x 的
倍数的方案数,还是利用二项式反演解答。