基础数论算法(⑩) Catalan数与Stirling数

严格的说,这一节已经脱离了数论的范畴……
数学真tm开心啊,我不想打代码了


Catalan数

Catalan数的公式

Catalan数的递推公式:
f(n)=n1i=0f(i)f(ni1)
f(n)=f(n1)×(4n2)n+1
Catalan数的通项公式:
f(n)=Cn2nCn12n f(n)=Cn2nn+1
总之先把公式摆出来。
Catalan数是用于解决一类计数问题的重要工具。最经典的应用就是2003年普及组的栈,这道题用Catalan打表可以直接过。
接下来,我们用h(n)代表Catalan数的通项,从两类基本问题出发来看一些经典的例题。

Catalan数的典型问题

栈的计数

栈要先进后出,所以进栈是出栈的先决条件。因此,这里的栈的排序就不是 Cn2n 。那么是什么呢?答案是卡特兰数。
为什么呢?如果第0个数是进栈,那么第2i+1个数是对应的出栈。因为如果是个偶数,操作就是奇数个,这显然是不可能的。所以我们不妨设对栈的操作为f(2n),而 f(2n)=2n1i=0f(2i)f(2n2i2) ,这个对应的恰好是Catalan数。

变形:

括号匹配

把(看做压入栈,)看做pop,那么就相当于栈的进出计数,f(2n)为catalan数

不交叉划分

将1-2n划分为n个二元组,使得每个二元组与其它二元组相离或内含。相当于括号匹配,f(2n)=h(n)

非降路径

从(0,0)到(n,n)且不越过直线y=x(可触碰),每次走一格,有多少种?将向上看做入栈,向右看做出栈,则转化为栈的计数,f(2n)=h(n)

排队买票

一排人只有10元和5元,票价5元,有多少种计数方式使得售票员能找开钱?将10元看做入栈,5元看做出栈,f(2n)=h(n)

二叉树计数划分

二叉树有n个节点,那么所能组成的形态为何?设第n个点为根节点,显然答案为 n1i=0f(i)f(ni1) ,Catalan数

变形:

连乘/矩阵链乘法计数

求n个数相乘的运算顺序,相当于将每个*看做一个二叉树的根节点,f(n)=h(n-1)

圆上连线问题

圆周上有2n个点,求连线两两不相交的可能总数。将圆周上的点从1开始按某一个方向标号,如果A与B配对,那么AB之间的两个弧上一定都是偶数个点,否则就会两边各有一个点配对使连线与AB相交。因此,这就相当于将AB作为一颗二叉树的根节点,即f(2n)=h(n)

凸三角形划分

确定一个顶点O,再任选两个相邻顶点连线构成一个三角形,可以作为一个二叉树的根节点。剩余的两部分同理,而n边形可以看做n-2个三角形构成,所以f(n)=h(n-2)

阶梯矩形分割

将n层的阶梯分割为n个矩形,问分法数量。
这里写图片描述
我们看到,n层的阶梯一定有这样n个红色的小矩形,所以每一个矩形必须包含一个。并且一定有其中一个包含蓝色的矩形,因此,将这个矩形当做二叉树根节点,f(n)=h(n)

应用Catalan数

我觉得在知道这道题是Catalan数的时候往往是比赛已经结束的时候。因此,我们不妨采用一种方法:不完全归纳法。首先请记住Catalan数的前几项:1,2,5。看到这几个数就要有敏感。然后再来看Catalan数的适用条件往往是有一定限定的组合计数问题。如果是这样的话,不妨思考能否将题目中的条件转化为类似于出栈入栈的模型,或者是类似于找二叉树根节点的模型。
在应用时,直接写组合数公式是很不明智的,因为!运算往往会非常慢,而且容易超long long范围。所以一般情况下,我们求的是递推公式,复杂度 O(n2)

普遍的非降路径问题

为什么单另要说一说这个,大概是因为我第一次见到这个问题的时候就被它漂亮的解法感动到了。
求从(0,0)到(m,n)的非降路径数。首先从(0,0)到(m,n)有 Cnm+n 条路,而我们不妨从反面考虑,求一下穿过边界的通路数。
这里写图片描述
如上图,红-蓝这条线是我们原先的路径,而将红色部分翻折过去就得到了绿-蓝这条路线。显然所有的穿过中间轴的路径经过一次翻转之后都能得到这样的一条路径,注意翻转的最后一个小块,我们发现原本向上的小块变成了向右,此时所有的路径总数就是 Cn1m+n
因此,非降路径总数为 Cnm+nCn1m+n

Stirling数

并不像Catalan数那样神奇,Stirling数更类似一个模板

第二类Stirling数

有一个很奇怪的问题:将n个元素构成的集合划分在k个非空集合中有多少种分法?来考虑一下,我们用S(n,k)来描述这个问题,那么:
1>S(n,n)=1
2>S(n,0)=0
3>S(n,k)=kS(n-1,k)+S(n-1,k-1)
第一个是显然的,第二个是规定。关键是第三个,我们如何理解呢?
不妨思考一下,这里我们鲜见的使用正推的思想。假定现在我们已经放完了n-1个元素,只剩下最后的一个。
这时,我们有两种情况:
一种是前n-1个元素已经占据了前k-1个盒子,那么此时选择只有一个,就是侵占最后的一个盒子,方案数就是S(n-1,k-1)
另一种是前n-1个元素已经占满了k个盒子。这就意味着最后一个元素可以在k个盒子中任选一个,因此方案数是k·S(n-1,k)
综上所述,S(n,k)=kS(n-1,k)+S(n-1,k-1)

一些变化

n个球放进k个无区别盒子:S(n,k)
n个球放进k个有区别盒子: AkkS(n,k)=k!S(n,k)
n个球放进无区别的盒子:B(n)

这里的B(n)是贝尔数,含义为 nk=0S(n,k) 由于没有规定盒子的空的个数,所以就这么做就可以辣

n个球放进k个无区别的可以为空的盒子: ki=0S(n,i)

正面不行用反面,枚举所有非空就行,不过记得预处理降低复杂度

n个球放进k个有区别的可以为空的盒子: ki=0AikS(n,i)

哈哈哈,你是不是学傻了?这样的话,每个球有k个选择,所以就是 kn ,当然由此可以求出Stirling数的通项公式

通项公式

可能你会好奇,这玩意是不是有通项公式?当然有啊,不过你背不会。它是长这个样子的:
这里写图片描述
嗯,还是老老实实写递推吧,你说呢?

第一类Stirling数

为什么要先说第二类再说第一类?因为大家都是这么干的第二类更类似一个组合,而第一类更类似一个排列。
第一类Stirling数描述的是,从n个元素中组成m个圆排列,用符号s(n,m)表示。
至于圆排列是什么,我们可以想象成一堆人站成一个圈。因此,对于一个圆排列来说,插入到每个人的旁边都能形成不一样的新排列。
同样采用正推的思想解决问题。假设n-1个元素已经完成,那么对于第n个元素,有两种情况:一种是前n-1个元素形成m-1个圆排列,那么第n个元素自成一家,有s(n-1,m-1)个排列;另一种是前n-1个元素形成了m个圆排列,那么他可以插到(n-1)个元素中任意一个的左边,这时就有(n-1)·s(n-1,m)种情况。
因此,我们得出:s(n,m)=s(n-1,m-1)+(n-1)·s(n-1,m)

一道例题

有n个仓库,每个仓库有两把钥匙,共2n把钥匙。同时又有n位官员分成m个不同的部,部中的官员数量和管理的仓库数量一致。那么有多少方案使得,同部的所有官员可以打开所有本部管理的仓库,而无法打开其他部管理的仓库?
题是什么意思呢?其实很有趣,这时个俄罗斯套娃,在第一个仓库中放第二个仓库的钥匙,第n个仓库放第一个仓库的钥匙,以此类推,这样官员依循钥匙的指引,就可以将所有的仓库转遍。
因此,钥匙和仓库实质上形成了一个圆排列,可以表示为s(n,m),但要考虑一下官员是不同的,毕竟生物存在遗传和变异的现象。故结果为n!·s(u,m)

参考资料

大概是参考最多的一次吧……
http://blog.csdn.net/ivy_uu/article/details/72835696
http://blog.csdn.net/wuzhekai1985/article/details/6764858
http://www.cnblogs.com/wuyuegb2312/p/3016878.html
https://fredia.github.io/2017/03/18/%E7%A5%9E%E5%A5%87%E7%9A%84%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0/
http://blog.csdn.net/duanruibupt/article/details/6869431
http://lanqi.org/interests/10939/
http://blog.csdn.net/qq_25221835/article/details/47404819
https://baike.baidu.com/item/%E6%96%AF%E7%89%B9%E6%9E%97%E6%95%B0/4938529?fr=aladdin&fromid=8517487&fromtitle=stirling%E6%95%B0#3_1