50.组合数学

组合数学

容斥原理

容斥原理的简单形式,设 AB 是分别具有性质 P1P2 的有限集,有

AB=|A|+|B||AB|

e.g. 求正整数 1n 中,既不是 2 的倍数也不是 3 的倍数的数的个数

S={1,2,,n}A2 的倍数,B3 的倍数,那么答案就是 |S||AB|

由于 |AB|=|A|+|B||AB|, 所以答案就是 nn2n3+n6

e.g. 求由 n 个元素 1,2,,n 全排列中,满足 12 不相邻,34 不相邻的排列数

A12 相邻,B34 相邻,那么答案就是 n!|AB|

所以答案就是 n!2(n1)!2(n1)!+4(n2)!

考虑三个子集的容斥原理

|ABC|=|A|+|B|+|C||AB||AC||BC|+|ABC|

推广到 n 个集合

S 是一个有限集,A1,A2,,AnSn 个子集,那么

|A1A2An|=i=1n(1)i11j1<j2<<jin|Aj1Aj2Aji|

我们对答案取补集的形式也很常见:

S|A1A2An|=i=0n(1)i1j1<j2<<jin|Aj1Aj2Aji|

这里需要定义 ||=S

e.g. m 件不同的物品,分配给 n 个人,要求每个人至少要分得一件物品,求不同的分配方案数

S= 总方案数,Ai=i 个人没有分到物品的方案数

答案就是

S|A1A2An|=i=0n(1)i1j1<j2<<jin|Aj1Aj2Aji|

|Aj1Aj2Aji| 就是 ni 个人分配 m 件物品的方案数,即 C(n,ni)×(ni)m=C(n,i)×(ni)m

得到了答案的递推式:

i=0n(1)iC(n,i)×(ni)m

e.g. 错排问题:p 是一个排列,满足 pii 的数的个数称为错排数,求错排数

S 是所有排列数,Aii 不在 pi 的位置的排列数

|Si=1nAi|=i=0nCni(ni)!

容斥原理的符号形式

S 是一个有限集,a1,a2,,ann 种性质

通过符号形式,我们可以把容斥原理改成多项式来处理

则,容斥原理可以写成:

N((1a1)(1a2)(1an))=i=0n(1)i 1j1<j2<<jinN(aj1,aj2,,aji)

e.g. 求正整数 1n 中,既不是 2 的倍数,也不是 3 的倍数,但是 5 的倍数的数的数量

a12 的倍数,a23 的倍数, a35 的倍数

答案就是 N((1a1)(1a2)a3)=N(a3a1a3a2a3+a1a2a3)

特殊的数

Catalan 数

Catalan 数有三种计算公式

公式 1

Cn=1n+1(2nn)=(2nn)(2nn+1)=(2nn)(2nn1)

公式 1 可以从一个基本模型推导出来:把 n1n0 排成一行,使这一行的任意 k 个数中 1 的数量总是大于或等于 0 的数量,这样的排列一共有 Cn

公式 2

Cn=k=0nCkCn1k, C0=1

公式 3

Cn=4n2n+1Cn1

模型 1:棋盘问题

一个 nn 列的棋盘,从左上角走到右上角,一直在对角线右下方走,不穿过主对角线,走法有多少种?

对方向编号,向上为 0,向右为 1,那么从左下角到右上角一定会经过 n1n0,如果第 k 步之前 0 的个数超过 1 的个数了,就说明一定超过对角线了

从左下角到右上角的路线方案总共有 3 种:

显然, (2nn)=A+B+C,现在的问题转化成如何求 B+C

我们需要找一条穿过对角线或者完全在对角线上方的路线,然后按照一条虚线映射

image.png

我们发现,一条穿过对角线的路线和新路线是一一对应的,而新路线的方案数是 (2nn+1)=(2nn1),从 2n 个里面选 n+10,选 n11

所以 Cn=(2nn)(2nn1)

使用生成函数推导

根据递推公式:

Cn=k=0nCkCn1k

定义生成函数 f(x)=n=0Cnxn,那么:

C(x)=n0Cnxn=1+x+xn1i=0nCiCn1xn=1+x+x(C(x)21)=1+xC2(x)

考虑类似于实数的二次方程,解得:

C(x)=1+14x2x

其中:

(14x)12=n=0(12n)(4)nxn=n012(121)(122)(12n+1)n!(4)nxn

所以:

C(x)=n012(121)(122)(12n)(n+1)!(4)nxnC(x)=12(121)(122)(12n)(n+1)!(4)n=12(12)(32)(2n12)12n(n+1)!(n)!(4)n=1352n1242n(n+1)!n!=(2n)!(n+1)!n!=1n+1(2nn)

斯特林数

第二类斯特林数

考虑一个问题:

n 个互不相同的求球,放到 k 个互不区分的盒子里,每个盒子里至少要有一个球,球方案数

用动态规划来解决这个问题

f(n,k)=kf(n1,k)+f(n1,k1)

我们定义 f(n,k) 为第二类斯特林数,记作 S2(n,k),这种方法的时间复杂度为 O(nk)

考虑用容斥原理求出 O(klogn) 的递推式

先把盒子按照 1k 编号,设 ai 表示第 i 个盒子没有球,答案就是

N((1a1)(1ak))=i=0k(1)i(ki)(ki)n=S2(n,k)×k!

则我们能得到第二类斯特林数的通项公式

{nk}=1k!i=0k(1)i(ki)(ki)n

第二类斯特林数还有一个重要的公式

nm=k=0m{mk}nk

可以思考组合意义来理解,把 m 个相互区分的球放到 n 个相互区分盒子里面,朴素的方法就是 nm

我们可以先去 k 个盒子放球,要求每个盒子中至少有一个球,这个的方案数就是 CnkS2(m,k)k!=S2(m,k)nk

第二类斯特林数有关于 n 的指数生成函数

n0S2(n,k)xnn!=1k!(exp(x)1)k

这样就可以求一行的斯特林数,就是 n 固定

我们有

{nk}=1k!i=0k(1)i(ki)(ki)n=i=0k(1)i1i!×1(ki)!(k1)n

f(x)=i=0n(1)i1i!xi,g(x)=j=0n1j!jn

所以

{nk}=[xk]f(x)g(x)

总时间复杂度为 O(nlogn)

分拆数

n 个无标号的球分配到 k 和无标号的盒子的方案数,每个盒子不为空,记为 p(n,k)

有递推关系

p(n,k)=p(n1,k1)+p(nk,k)

image-20241101001500147

构造一种排列方式,一共有 k 行,每一行的球的数量都比上一行少,每一列考虑:

关于 n 的常生成函数:n0p(n,k)xn=xki=1k11xi

如何快速求 p(n,k):先取 ln 再 exp

n 个无标号的球分配到一些无编号盒子,每个盒子不为空的方案数,记为 p(n)

p(n)=k=1np(n,k)

递推关系

p(n)=k1(1)k1(p(n3k2k2)+p(n3k2+k2))

常生成函数

n0p(n)xn=i111xi

这个表展示了一些经典的分配问题

image-20241101003947933