概念
- 斯特林数(Stirling number)是由18世纪数学家James Stirling提出的两类数。
- 第一类:轮换数,将n个数排成k个非空的环(圆排列,有序)的方案数,用s(n,m)或[nk]表示。还分为无符号第一类斯特林数su(n,m)和带符号第一类斯特林数 ss(n,m)。
- 第二类:子集数,将n个数排成k个非空集合(集合内无序)的方案数,用S(n,m)或{nk}表示。
第一类斯特林数
边界条件&&递推式
- 先考虑无符号第一类斯特林数su(n,m)。
- 根据定义,易得边界条件:
s(n,k)=⎩⎪⎨⎪⎧010n<kn=kn>0 ∧ k=0
- 假设现在已知s(n−1,k−1),我们要加入一个新数n。它可以考虑自己形成一个新的环,或者插入任意一个已有的数后面,因此:[nk]=[n−1k−1]+(n−1)[n−1k]
- 有符号的第一类斯特林数ss(n,k)与此类似。其递推式为:ss(n,k)=(−1)n+ksu(n,k)=ss(n−1,k−1)−(n−1)×ss(n−1,k)
- 时间&空间复杂度:O(n2)。
与上升/下降幂的关系
- 第一类斯特林数与上升幂xn=x(x+1)(x+2)⋯(x+n−1)满足如下所示的关系:
xn=k=1∑nsu(n,k)×xk
- 亦即第一类斯特林数表现为xn的展开形式的各项系数。
- 该式子可利用su(n,m)的递推式通过数学归纳法来证明。但其亦有简单的组合意义:
- n个点,构成若干个环,要求一个环中所有点颜色相同,不同环不作要求。那么我们可以枚举环的组成(∑k=1nsu(n,k)),再给每个环分配颜色(xk);从另一个角度想,我们按编号从小到大加入每个点,每个点可在x种颜色中选择一种并自己形成一个新的环,亦可在前n−1个点中选择一个点接在它后面并继承它的颜色,那么操作方案数即为xn。
- 上式加以变形可得到与下降幂xn=x(x−1)(x−2)⋯(x−n+1)的关系:
xn=k=1∑n(−1)n−k×su(n,k)×xk=k=1∑nss(n,k)×xk
- 这是因为我们把xn展开后,会发现它的各项系数的绝对值与xn一致,只是正负性会交错排列。
较为快速的求法
- 考虑多项式F(x)=∏i=0n−1(x+i)的系数。
- F(x)=xn=∑k=1n[kn]xk=∑k=0n[kn]xk
- 因此,F(x)的k次项系数即为[kn]。
- 考虑快速地求解[kn]。
- 当有模数的时候,可以分治NTT求解F(x)的各项系数(可以忽略掉i=0时的(x+i))。我们进行CDQ分治,区间[2l−1,2r]表示(x+l)(x+l+1)(x+l+2)⋯(x+r)的各项系数。记m=2l+r,每次先求解区间[2l−1,2m]和区间[2m+1,2r],尔后再合并。
- 时间复杂度:O(nlog22n);空间复杂度:O(n)。
第二类斯特林数
回顾一下定义
- 第二类斯特林数:子集数,将n个数排成k个非空集合(集合内无序)的方案数,用S(n,m)或{nk}表示。
边界条件&&递推式
- 随便思考一下即可发现,边界条件与第一类斯特林数一致:
S(n,k)=⎩⎪⎨⎪⎧010n<kn=kn>0 ∧ k=0
- 假设现在已知S(n−1,k−1),要加入新数n。它可以自己形成一个新的集合,或者加进先前已有的任意一个集合中去,于是:{nk}={n−1k−1}+k{n−1k}
- 时间&空间复杂度:O(n2)。
与下降幂的关系
- 第二类斯特林数与下降幂xk满足如下所示的关系:
xn=k=0∑nS(n,k)×xk
- 与前面的一样,这个式子可以用数学归纳法证明,亦有组合意义:
- 假设我们用x种颜色为n个点染色,方案数显然是xn;而我们也可以枚举同种颜色的集合是什么(∑k=0nS(n,k)),然后从x种颜色中选出不同的颜色赋给这些集合(xk)。
通项公式
- 转换模型。不难发现S(n,k)等价于:将n个不同的球放入m个无差别的盒子中,要求盒子非空的方案数。
- 我们先考虑盒子有差别的情况。
- 考虑容斥。枚举空盒数i,在m个盒子中选i个即为(im);那么,n个球可以放进剩下的m−i个盒子中,即为(m−i)n。容斥系数显然为(−1)i。(当然,严谨证明还是得推式子)
- 最后,消除盒子的差别,整体乘上一个m!1。
- 以上说明过于感性,下面我们来理性一下。
- 我们之前已经得出了:mn=∑i=0n{in}mi
- 把mi拆开来就变成:∑i=0n(kn){kn}x!
- 那么,根据二项式反演,上式等价于:{mn}m!=∑i=0m(−1)i(im)(m−i)n
- 然后,我们把m!丢到右边去。
- 至此,我们得到了第二类斯特林数的通项公式:
{nm}=m!1i=0∑m(−1)i(im)(m−i)n=i=0∑mi!(m−i)!(−1)i(m−i)n
- 可以考虑预处理i!(m−i)!1。单组询问的话,也可以预处理(m−i)n。
- 时间复杂度:O(mlogM)或O(m)。(M为模数)
- 如果我们要快速地求S(n,0)∼S(n,m)怎么破?我们发现通项公式中,i!(−1)i只与i有关,(m−i)!(m−i)n只与m−i有关。所以可设两个多项式,用一个FFT/NTT,即可在O(mlogm)的时间内求出。
与自然数幂和
- 第二类斯特林数的一大亮点是可以
龟快速求自然数幂和。
- 记F(n)=∑i=1nik。我们来现场推一波式子:
F(n)=i=1∑nj=0∑k{kj}ij=i=1∑nj=0∑k{kj}j!(ij)=j=0∑k{kj}j!i=j∑n(ij)
- 现在已经可以O(nk)求解了。但是我们想更快。
- 先给出一个结论:∑i=jn(ji)=(j+1n+1)。
- 这个东西的证明,可以根据组合数的递推式依次展开(j+1n+1)来得到:
(n+1j+1)=(nj)+(nj+1)=(nj)+(n−1j)+(n−1j+1)=(nj)+(n−1j)+(n−2j)+(n−2j+1)=(nj)+(n−1j)+⋯+(jj)+(jj+1)=(nj)+(n−1j)+⋯+(jj)
- 也可以考虑组合意义:n+1个数排成一排,选j+1个,枚举第一个数选的位置,剩下的数再选j个,于是就成了上面的式子。
- 然后我们可以继续化简。
- 接着上面的队形:
F(n)=j=0∑k{kj}j!i=j∑n(ij)=j=0∑k{kj}j!(n+1j+1)=j=0∑k{kj}j+1(n+1)j+1
- {jk}的值可以O(k2)或O(klogk)预处理。而(n+1)j+1是连续的j+1个自然数的乘积,则其一定是j+1的倍数,因此不必逆元。(当然,假如(n+1)太大,要先模,那就得逆元了)逆元可以O(k)预处理,因此单次询问复杂度为O(k)。
两类斯特林数之间的关系
i=0∑nS(n,i)s(i,m)=i=0∑ns(n,i)S(i,m)
- 这是为什么呢?我觉得应该可以数学归纳法,在此不作证明。