斯特林数

数学 / 组合数学

本地源文件:docs/math__combinatorics__stirling.md

斯特林数

第二类斯特林数(Stirling Number)

为什么先介绍第二类斯特林数

虽然被称作「第二类」,第二类斯特林数却在斯特林的相关著作和具体数学中被首先描述,同时也比第一类斯特林数常用得多.

第二类斯特林数 (斯特林子集数){𝑛𝑘}{nk},也可记做 𝑆(𝑛,𝑘)S(n,k),表示将 𝑛n 个两两不同的元素,划分为 𝑘k 个互不区分的非空子集的方案数.

递推式

{𝑛𝑘}={𝑛−1𝑘−1}+𝑘{𝑛−1𝑘}{nk}={n−1k−1}+k{n−1k}

边界是 {𝑛0} =[𝑛 =0]{n0}=[n=0]

考虑用组合意义来证明.

我们插入一个新元素时,有两种方案:

  • 将新元素单独放入一个子集,有 {𝑛−1𝑘−1}{n−1k−1} 种方案;
  • 将新元素放入一个现有的非空子集,有 𝑘{𝑛−1𝑘}k{n−1k} 种方案.

根据加法原理,将两式相加即可得到递推式.

通项公式

{𝑛𝑚}=𝑚∑𝑖=0(−1)𝑚−𝑖𝑖𝑛𝑖!(𝑚−𝑖)!{nm}=∑i=0m(−1)m−iini!(m−i)!

使用容斥原理证明该公式.设将 𝑛n 个两两不同的元素,划分到 𝑖i 个两两不同的集合(允许空集)的方案数为 𝐺𝑖Gi,将 𝑛n 个两两不同的元素,划分到 𝑖i 个两两不同的非空集合(不允许空集)的方案数为 𝐹𝑖Fi

显然

𝐺𝑖=𝑖𝑛𝐺𝑖=𝑖∑𝑗=0(𝑖𝑗)𝐹𝑗Gi=inGi=∑j=0i(ij)Fj

根据二项式反演

𝐹𝑖=𝑖∑𝑗=0(−1)𝑖−𝑗(𝑖𝑗)𝐺𝑗=𝑖∑𝑗=0(−1)𝑖−𝑗(𝑖𝑗)𝑗𝑛=𝑖∑𝑗=0𝑖!(−1)𝑖−𝑗𝑗𝑛𝑗!(𝑖−𝑗)!Fi=∑j=0i(−1)i−j(ij)Gj=∑j=0i(−1)i−j(ij)jn=∑j=0ii!(−1)i−jjnj!(i−j)!

考虑 𝐹𝑖Fi 与 {𝑛𝑖}{ni} 的关系.第二类斯特林数要求集合之间互不区分,因此 𝐹𝑖Fi 正好就是 {𝑛𝑖}{ni} 的 𝑖!i! 倍.于是

{𝑛𝑚}=𝐹𝑚𝑚!=𝑚∑𝑖=0(−1)𝑚−𝑖𝑖𝑛𝑖!(𝑚−𝑖)!{nm}=Fmm!=∑i=0m(−1)m−iini!(m−i)!

同一行第二类斯特林数的计算

「同一行」的第二类斯特林数指的是,有着不同的 𝑖i,相同的 𝑛n 的一系列 {𝑛𝑖}{ni}.求出同一行的所有第二类斯特林数,就是对 𝑖 =0..𝑛i=0..n 求出了将 𝑛n 个不同元素划分为 𝑖i 个非空集的方案数.

根据上面给出的通项公式,卷积计算即可.该做法的时间复杂度为 𝑂(𝑛log⁡𝑛)O(nlog⁡n)

下面的代码使用了名为 poly 的多项式类,仅供参考.

实现

---|---

实现

---|---

同一列第二类斯特林数的计算

「同一列」的第二类斯特林数指的是,有着不同的 𝑖i,相同的 𝑘k 的一系列 {𝑖𝑘}{ik}.求出同一列的所有第二类斯特林数,就是对 𝑖 =0..𝑛i=0..n 求出了将 𝑖i 个不同元素划分为 𝑘k 个非空集的方案数.

利用指数型生成函数计算.

一个盒子装 𝑖i 个物品且盒子非空的方案数是 [𝑖 >0][i>0].我们可以写出它的指数型生成函数为 𝐹(𝑥) =+∞∑𝑖=1𝑥𝑖𝑖! =e𝑥 −1F(x)=∑i=1+∞xii!=ex−1.经过之前的学习,我们明白 𝐹𝑘(𝑥)Fk(x) 就是 𝑖i 个有标号物品放到 𝑘k 个有标号盒子里的指数型生成函数,那么除掉 𝑘!k! 就是 𝑖i 个有标号物品放到 𝑘k 个无标号盒子里的指数型生成函数.

{𝑖𝑘} =[𝑥𝑖𝑖!]𝐹𝑘(𝑥)𝑘!{ik}=[xii!]Fk(x)k!,𝑂(𝑛log⁡𝑛)O(nlog⁡n) 计算多项式幂即可.

另外,exp⁡𝐹(𝑥) =+∞∑𝑖=0𝐹𝑖(𝑥)𝑖!exp⁡F(x)=∑i=0+∞Fi(x)i! 就是 𝑖i 个有标号物品放到任意多个无标号盒子里的指数型生成函数(EXP 通过每项除以一个 𝑖!i! 去掉了盒子的标号).这其实就是贝尔数的生成函数.

这里涉及到很多「有标号」「无标号」的内容,注意辨析.

实现

---|---

## 第一类斯特林数(Stirling Number)

**第一类斯特林数** (斯特林轮换数)[𝑛𝑘][nk]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),也可记做 𝑠(𝑛,𝑘)s(n,k)![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),表示将 𝑛n![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 个两两不同的元素,划分为 𝑘k![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 个互不区分的非空轮换的方案数.

一个轮换就是一个首尾相接的环形排列.我们可以写出一个轮换 [𝐴,𝐵,𝐶,𝐷][A,B,C,D]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),并且我们认为 [𝐴,𝐵,𝐶,𝐷] =[𝐵,𝐶,𝐷,𝐴] =[𝐶,𝐷,𝐴,𝐵] =[𝐷,𝐴,𝐵,𝐶][A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7),即,两个可以通过旋转而互相得到的轮换是等价的.注意,我们不认为两个可以通过翻转而相互得到的轮换等价,即 [𝐴,𝐵,𝐶,𝐷] ≠[𝐷,𝐶,𝐵,𝐴][A,B,C,D]≠[D,C,B,A]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7).

### 递推式

[𝑛𝑘]=[𝑛−1𝑘−1]+(𝑛−1)[𝑛−1𝑘][nk]=[n−1k−1]+(n−1)[n−1k]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

边界是 [𝑛0] =[𝑛 =0][n0]=[n=0]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7).

该递推式的证明可以考虑其组合意义.

我们插入一个新元素时,有两种方案:

  * 将该新元素置于一个单独的轮换中,共有 [𝑛−1𝑘−1][n−1k−1]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 种方案;
  * 将该元素插入到任何一个现有的轮换中,共有 (𝑛 −1)[𝑛−1𝑘](n−1)[n−1k]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 种方案.

根据加法原理,将两式相加即可得到递推式.

### 通项公式

第一类斯特林数没有实用的通项公式.

### 同一行第一类斯特林数的计算

类似第二类斯特林数,我们构造同行第一类斯特林数的生成函数,即

𝐹𝑛(𝑥) =𝑛∑𝑖=0[𝑛𝑖]𝑥𝑖Fn(x)=∑i=0n[ni]xi![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

根据递推公式,不难写出

𝐹𝑛(𝑥) =(𝑛 −1)𝐹𝑛−1(𝑥) +𝑥𝐹𝑛−1(𝑥)Fn(x)=(n−1)Fn−1(x)+xFn−1(x)![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

于是

𝐹𝑛(𝑥) =𝑛−1∏𝑖=0(𝑥 +𝑖) =(𝑥+𝑛−1)!(𝑥−1)!Fn(x)=∏i=0n−1(x+i)=(x+n−1)!(x−1)!![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

这其实是 𝑥x![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 的 𝑛n![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 次上升阶乘幂,记做 𝑥――𝑛xn―![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7).这个东西自然是可以暴力分治乘 𝑂(𝑛log2⁡𝑛)O(nlog2⁡n)![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 求出的,但用上升幂相关做法可以 𝑂(𝑛log⁡𝑛)O(nlog⁡n)![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 求出,详情见 [多项式平移 | 连续点值平移](../../poly/shift/#同一行第一类无符号-stirling-数).

### 同一列第一类斯特林数的计算

仿照第二类斯特林数的计算,我们可以用指数型生成函数解决该问题.注意,由于递推公式和行有关,我们不能利用递推公式计算同列的第一类斯特林数.

显然,单个轮换的指数型生成函数为

𝐹(𝑥) =𝑛∑𝑖=1(𝑖−1)!𝑥𝑖𝑖! =𝑛∑𝑖=1𝑥𝑖𝑖F(x)=∑i=1n(i−1)!xii!=∑i=1nxii![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

它的 𝑘k![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 次幂就是 [𝑖𝑘][ik]![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 的指数型生成函数,𝑂(𝑛log⁡𝑛)O(nlog⁡n)![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 计算即可.

实现

---|---

应用

上升幂与普通幂的相互转化

我们记上升阶乘幂 𝑥――𝑛 =∏𝑛−1𝑘=0(𝑥 +𝑘)xn―=∏k=0n−1(x+k)

则可以利用下面的恒等式将上升幂转化为普通幂:

𝑥――𝑛=∑𝑘[𝑛𝑘]𝑥𝑘xn―=∑k[nk]xk

如果将普通幂转化为上升幂,则有下面的恒等式:

𝑥𝑛=∑𝑘{𝑛𝑘}(−1)𝑛−𝑘𝑥――𝑘xn=∑k{nk}(−1)n−kxk―

下降幂与普通幂的相互转化

我们记下降阶乘幂 𝑥𝑛―― =𝑥!(𝑥−𝑛)! =∏𝑛−1𝑘=0(𝑥 −𝑘)xn―=x!(x−n)!=∏k=0n−1(x−k)

则可以利用下面的恒等式将普通幂转化为下降幂:

𝑥𝑛=∑𝑘{𝑛𝑘}𝑥𝑘――xn=∑k{nk}xk―

如果将下降幂转化为普通幂,则有下面的恒等式:

𝑥𝑛――=∑𝑘𝑛𝑘𝑛−𝑘𝑥𝑘xn―=∑knkn−kxk

多项式下降阶乘幂表示与多项式点值表示的关系

在这里,多项式的下降阶乘幂表示就是用

𝑓(𝑥)=𝑛∑𝑖=0𝑏𝑖𝑥𝑖――f(x)=∑i=0nbixi―

的形式表示一个多项式,而点值表示就是用 𝑛 +1n+1 个点

(𝑖,𝑎𝑖),𝑖=0..𝑛(i,ai),i=0..n

来表示一个多项式.

显然,下降阶乘幂 𝑏b 和点值 𝑎a 间满足这样的关系:

𝑎𝑘=𝑛∑𝑖=0𝑏𝑖𝑘𝑖――ak=∑i=0nbiki―

𝑎𝑘=𝑛∑𝑖=0𝑏𝑖𝑘!(𝑘−𝑖)!𝑎𝑘𝑘!=𝑘∑𝑖=0𝑏𝑖1(𝑘−𝑖)!ak=∑i=0nbik!(k−i)!akk!=∑i=0kbi1(k−i)!

这是一个卷积形式的式子,我们可以在 𝑂(𝑛log⁡𝑛)O(nlog⁡n) 的时间复杂度内完成点值和下降阶乘幂的互相转化.

习题

参考资料与注释

  1. Stirling Number of the First Kind - Wolfram MathWorld
  2. Stirling Number of the Second Kind - Wolfram MathWorld
本页面最近更新: 2026/1/7 08:56:54,更新历史 发现错误?想一起完善?在 GitHub 上编辑此页! 本页面贡献者:Ir1d, Enter-tainer, Fei Natsuka, StudyingFather, Tiphereth-A, Xeonacid, MegaOwIer, sshwy, iamtwz, ksyx, caijianhong, CCXXXI, Great-designer, H-J-Granger, isdanni, Konano, LLLMMKK, Menci, purple-vine, shuzhouliu, YanagiOrigami 本页面的全部内容在CC BY-SA 4.0SATA 协议之条款下提供,附加条款亦可能应用