下面提到的内容均属组合数学范畴。
前言
由于式子较多,为增强直观性,笔者将一改以往的笔风,用 ( n m ) \displaystyle\binom{n}{m} (mn) 表示组合数 C n m \operatorname{C}_n^m Cnm。同理,笔者分别会用 [ n k ] \begin{bmatrix}n \\ k\end{bmatrix} [nk] 和 { n k } \begin{Bmatrix}n \\ k\end{Bmatrix} { nk} 表示第一类斯特林数 s ( n , k ) s(n, k) s(n,k) 和第二类斯特林数 S ( n , k ) S(n, k) S(n,k)。
阅读这篇文章前,您需要较为熟练地掌握组合数、排列数(特别是圆排列)的定义和公式,以及常见的组合恒等式。
前置知识
上升幂和下降幂
- 定义 x n ‾ x^{\overline{n}} xn 为 x x x 的 n n n 次上升阶乘幂,又称上升幂。它的值等于 ∏ i = 0 n ( x + i ) \prod_{i = 0}^n (x + i) ∏i=0n(x+i)。
- 定义 x n ‾ x^{\underline{n}} xn 为 x x x 的 n n n 次下降阶乘幂,又称下降幂。它的值等于 ∏ i = 0 n ( x − i ) \prod_{i = 0}^n (x - i) ∏i=0n(x−i)。
上升幂和下降幂的转换公式(请读者自主完成证明):
( − x ) n ‾ = ( − 1 ) n x n ‾ ( − x ) n ‾ = ( − 1 ) n x n ‾ (-x)^{\overline{n}} = (-1)^n x^{\underline{n}} \\ (-x)^{\underline{n}} = (-1)^n x^{\overline{n}} (−x)n=(−1)nxn(−x)n=(−1)nxn
实际上,上升幂和下降幂与普通幂之间也有转换公式,不过由于公式中存在斯特林数,因此将在下文提及。
普通生成函数
通俗的讲,对于一个数列 a n a_n an,它的普通生成函数(简称 OGF \operatorname{OGF} OGF)为一个多项式:
f ( x ) = ∑ i = 0 ∞ a i x i f(x) = \sum_{i = 0}^{\infin} a_ix^i f(x)=i=0∑∞aixi
(严谨地讲, f ( x ) f(x) f(x) 应该叫做形式幂级数,不过笔者并不了解其确切定义,因此这里用更通俗的方式解释。)
也就是说,对于多项式 f ( x ) f(x) f(x),有 a n = [ x n ] f ( x ) a_n = [x^n]f(x) an=[xn]f(x)。
如果我们能够得到这个多项式,那么我们也可以从它的系数中获取到这个序列。
同时,如果我们要对数列间做一些运算(如卷积),也可以通过对这个多项式做运算得到最终的结果。
第一类斯特林数
把 n n n 个互不相同的数分为 k k k 个圆排列,这样的方案数称为第一类斯特林数,也叫斯特林轮换数,记做 s ( n , k ) s(n, k) s(n,k),也记做 [ n k ] \begin{bmatrix}n \\ k\end{bmatrix} [nk]。
递推式
我们知道,如果在一个长为 n n n 的圆排列中插入一个数(一共有 n n n 个位置可以插入),形成的 n n n 种长为 n + 1 n + 1 n+1 的圆排列是互不相同的,因为它们互相之间不可以通过轮换得到。
所以,第一类斯特林数有递推公式:
[ n k ] = [ n − 1 k − 1 ] + ( n − 1 ) [ n − 1 k ] \begin{bmatrix}n \\ k\end{bmatrix} = \begin{bmatrix}n - 1 \\ k - 1\end{bmatrix} + (n - 1) \begin{bmatrix}n - 1 \\ k\end{bmatrix} [nk]=[n−1k−1]+(n−1)[n−1k]
考虑从组合意义去证明:加入一个数,要么自己单独构成一个圆排列,要么插入已有的圆排列。前面说过,后者的方案数为 n − 1 n - 1 n−1。所以,根据加法原理,即可得到该递推式。
当然,该递推式也存在边界条件: [ n 0 ] = [ n = 0 ] \begin{bmatrix}n \\ 0\end{bmatrix} = [n = 0] [n0]=[n=0]。
由于第一类斯特林数不存在通项公式,这个递推式就显得尤为重要了,它将辅助证明下面的诸多结论。
常用公式
1. 和阶乘的关系:
n ! = ∑ i = 0 n [ n i ] n! = \sum_{i = 0}^n \begin{bmatrix}n \\ i\end{bmatrix} n!=i=0∑n[ni]
前者实际上是指 1 ∼ n 1\sim n 1∼n 的全排列。由于每一种排列中,圆排列的个数是一定的,那么我们可以考虑枚举所有的圆排列个数,把对应的第一类斯特林数相加即为答案。
2. 和上升幂的关系(上升幂转普通幂):
x n ‾ = ∑ i = 0 n [ n i ] x i x^{\overline{n}} = \sum_{i = 0}^n \begin{bmatrix}n \\ i\end{bmatrix} x^i xn=i=0∑n[ni]xi
证明:
-
考虑构造生成函数 f n ( x ) = ∑ i = 0 ∞ [ n i ] x i f_n(x) = \sum_{i = 0}^\infin \begin{bmatrix}n \\ i\end{bmatrix} x^i fn(x)=∑i=0∞[ni]xi.
∵ \because ∵ 根据递推式有 f n ( x ) = x f n − 1 ( x ) + ( n − 1 ) f n − 1 ( x ) f_n(x) = xf_{n - 1}(x) + (n - 1)f_{n - 1}(x) fn(x)=xfn−1(x)+(n−1)fn−1(x).
∴ \therefore ∴ 有 f n ( x ) = ( x + n − 1 ) f n − 1 ( x ) f_n(x) = (x + n - 1)f_{n - 1}(x) fn(x)=(x+n−1)fn−1(x).
∵ \because ∵ 当 n = 1 n = 1 n=1 时,有 f 1 ( x ) = x f_1(x) = x f1(x)=x.
∴ \therefore ∴ f n ( x ) = ∑ i = 0 n [ n i ] x i = x n ‾ f_n(x) = \sum_{i = 0}^n \begin{bmatrix}n \\ i\end{bmatrix} x^i = x^{\overline{n}} fn(x)=∑i=0n[ni]xi=xn.
以上证明过程也说明了:所有 n n n 相同的第一类斯特林数(也叫第 n n n 行第一类斯特林数)的生成函数是 x n ‾ x^{\overline{n}} xn。
-
受上面过程的启发,我们还可以考虑用数学归纳法证明。
显然当 n = 0 n = 0 n=0 或 n = 1 n = 1 n=1 时,原式左右两边相等。
设当前结论满足 n = m n = m n=m 的情况,求证当前结论也满足 n = m + 1 n = m + 1 n=m+1 的情况。
即证明: ∑ i = 0 n + 1 [ n + 1 i ] x i = ( x + n ) ∑ i = 0 n [ n i ] x i \sum_{i = 0}^{n + 1} \begin{bmatrix}n + 1 \\ i\end{bmatrix} x^i = (x + n) \sum_{i = 0}^n \begin{bmatrix}n \\ i\end{bmatrix} x^i ∑i=0n+1[n+1i]xi=(x+n)∑i=0n[ni]xi。
∑ i = 0 n + 1 [ n + 1 i ] x i = ∑ i = 0 n + 1 ( [ n i − 1 ] + n ⋅ [ n i ] ) x i = ∑ i = 0 n + 1 [ n i − 1 ] x i + ∑ i = 0 n + 1 n ⋅ [ n i ] x i = ∑ i = 0 n [ n i ] x i + 1 + n ⋅ ∑ i = 0 n [ n i ] x i = x ⋅ ∑ i = 0 n [ n i ] x i + n ⋅ ∑ i = 0 n [ n i ] x i = ( x + n ) ∑ i = 0 n [ n i ] x i \begin{aligned} &\sum_{i = 0}^{n + 1} \begin{bmatrix}n + 1 \\ i\end{bmatrix} x^i \\ = &\sum_{i = 0}^{n + 1} (\begin{bmatrix}n \\ i - 1\end{bmatrix} + n\cdot\begin{bmatrix}n \\ i\end{bmatrix}) x^i \\ = &\sum_{i = 0}^{n + 1} \begin{bmatrix}n \\ i - 1\end{bmatrix} x^i + \sum_{i = 0}^{n + 1} n\cdot\begin{bmatrix}n \\ i\end{bmatrix} x^i \\ = &\sum_{i = 0}^{n} \begin{bmatrix}n \\ i\end{bmatrix} x^{i + 1} + n \cdot\sum_{i = 0}^{n}\begin{bmatrix}n \\ i\end{bmatrix} x^i \\ = &x\cdot\sum_{i = 0}^{n} \begin{bmatrix}n \\ i\end{bmatrix} x^{i} + n \cdot\sum_{i = 0}^{n}\begin{bmatrix}n \\ i\end{bmatrix} x^i \\ = &(x + n) \sum_{i = 0}^n \begin{bmatrix}n \\ i\end{bmatrix} x^i \end{aligned} =====i=0∑n+1[n+1i]xii=0∑n+1([ni−1]+n⋅[ni])xii=0∑n+1[ni−1]xi+i=0∑n+1n⋅[ni]xii=0∑n[ni]xi+1+n⋅i=0∑n[ni]xix⋅i=0∑n[ni]xi+n⋅i=0∑n[ni]xi(x+n)i=0∑n[ni]xi
同一行第一类斯特林数的求法
根据递推公式,我们可以得到一个 O ( n 2 ) \mathcal{O}(n^2) O(n2) 的做法。
根据上面的结论(第 n n n 行第一类斯特林数的生成函数是 x n ‾ x^{\overline{n}} xn),我们有 O ( n log 2 2 n ) \mathcal{O}(n \log_2^2 n) O(nlog22n) 的做法:
因为上升幂本质上是若干个二项式相乘,所以我们分治后直接跑 NTT \operatorname{NTT} NTT 即可。
有没有更快的做法?当然有!
考虑倍增(它是多项式内容里的常客),当前求出了 x n ‾ x^{\overline{n}} xn,要求 x 2 n ‾ x^{\overline{2n}} x2n。
因为 x 2 n ‾ = x n ‾ ( x + n ) n ‾ x^{\overline{2n}} = x^{\overline{n}} (x + n)^{\overline{n}} x2n=xn(x+n)n,所以我们只要能够求出 ( x + n ) n ‾ (x + n)^{\overline{n}} (x+n)n,就能够做到 O ( n log 2 n ) \mathcal{O}(n \log_2 n) O(nlog2n) 了。
考虑生成函数的展开形式:已知 f ( x ) = ∑ i = 0 n a i x i f(x) = \sum_{i = 0}^n a_ix^i f(x)=∑i=0naixi,要求 f ( x + n ) = ∑ i = 0 n a i ( x + n ) i f(x + n) = \sum_{i = 0}^n a_i(x + n)^i f(x+n)=∑i=0nai(x+n)i。
我们对后面的这个式子做二项式展开:
∑ i = 0