【总结】斯特林数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86353854

前言

目前由于时间关系,只研究了第一类斯特林数。

有关第二类斯特林数的问题将尽快补上。

第一类斯特林数

第一类斯特林数的定义是:
[ n m ] n m {n \brack m}表示将n个数,放入m个圆排列的方案数
圆排列:只考虑元素之间的相对位置,不关心绝对位置。换言之可以像圆一样转动。类似置换群中的循环。

有一个很显然的递推式
[ n m ] = [ n 1 m 1 ] + ( n 1 ) [ n 1 m ] {n \brack m}={n-1 \brack m-1}+(n-1)*{n-1 \brack m}
解释是:n可以单独成一个圆排列。也可以加入到之前任何一个数左边。

不过这是 O ( n 2 ) O(n^2) 的,效率非常低下。

首先,有一个结论:
多项式 i = 0 i < n ( x + i ) x i [ n i ] \prod_{i=0}^{i<n}(x+i)展开后,x^i的系数正好就是{n \brack i}
证明比较简单。
考虑递推的过程,在最开始,将 [ 1 1 ] { 1\brack 1} 作为多项式的一次项系数。
然后,每次递推,系数的转移都可以看作: k i = k i 1 + ( t 1 ) k i k_i=k_{i-1}+(t-1)k_i ,其中 t t 表示当前多项式的最高次项。
那么相当于就是在原来的多项式的基础上,乘上了 ( x + t 1 ) (x+t-1) 这个多项式。
所以从第1层转移到第n层,就得依次乘上
i = 1 i < n ( x + i ) \prod_{i=1}^{i<n}(x+i)
加上最开始的一次项: i = 0 i < n ( x + i ) \prod_{i=0}^{i<n}(x+i)

由此,可以有一个 O ( n l o g 2 n ) O(nlog^2n) 的分治FFT/NTT的方法了。

现在,考虑更高效的算法。

假设当前要求的多项式是
i = 0 i < 2 n ( x + i ) \prod_{i=0}^{i<2n}(x+i)
可以先递归地求出前n项的乘积f
f ( x ) = i = 0 i < n ( x + i ) = i = 1 i n a i x i f(x)=\prod_{i=0}^{i<n}(x+i)=\sum_{i=1}^{i\leq n} a_ix^i
现在其实可以很简单地求出后n项的乘积 g ( x ) = i = n i < 2 n ( x + i ) g(x)=\prod_{i=n}^{i<2n}(x+i)

g ( x ) = i = 1 i n a i ( x + n ) i g(x)=\sum_{i=1}^{i\leq n}a_i(x+n)^i
由二项式定理得
= i = 1 i n a i j = 0 j i ( i j ) n i j x j =\sum_{i=1}^{i\leq n}a_i\sum_{j=0}^{j\leq i}{i \choose j}n^{i-j}x^j
= i = 1 i n j = 0 j i ( i j ) n i j a i x j =\sum_{i=1}^{i\leq n}\sum_{j=0}^{j\leq i}{i \choose j}n^{i-j}a_ix^j
= i = 1 i n j = 0 j i ( n i j ( i j ) ! ) ( a i i ! ) ( x j j ! ) =\sum_{i=1}^{i\leq n}\sum_{j=0}^{j\leq i}(\frac {n^{i-j}} {(i-j)!})(a_i*i!)(\frac {x^j} {j!})

这就是个裸的卷积了。

所以可以算出这部分,得到 g ( x ) g(x) 再乘上之前递归得到的 f ( x ) f(x) 就成功做到倍增了。

注意:当n为奇数时,要向下取整,最后再 O ( n ) O(n) 转移一次。


例题

2019雅礼集训permutation

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/86353854