版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86353854
前言
目前由于时间关系,只研究了第一类斯特林数。
有关第二类斯特林数的问题将尽快补上。
第一类斯特林数
第一类斯特林数的定义是:
[mn]表示将n个数,放入m个圆排列的方案数
圆排列:只考虑元素之间的相对位置,不关心绝对位置。换言之可以像圆一样转动。类似置换群中的循环。
有一个很显然的递推式
[mn]=[m−1n−1]+(n−1)∗[mn−1]
解释是:n可以单独成一个圆排列。也可以加入到之前任何一个数左边。
不过这是
O(n2)的,效率非常低下。
首先,有一个结论:
多项式
i=0∏i<n(x+i)展开后,xi的系数正好就是[in]
证明比较简单。
考虑递推的过程,在最开始,将
[11]作为多项式的一次项系数。
然后,每次递推,系数的转移都可以看作:
ki=ki−1+(t−1)ki,其中
t表示当前多项式的最高次项。
那么相当于就是在原来的多项式的基础上,乘上了
(x+t−1)这个多项式。
所以从第1层转移到第n层,就得依次乘上
i=1∏i<n(x+i)
加上最开始的一次项:
∏i=0i<n(x+i)
由此,可以有一个
O(nlog2n)的分治FFT/NTT的方法了。
现在,考虑更高效的算法。
假设当前要求的多项式是
∏i=0i<2n(x+i)
可以先递归地求出前n项的乘积f
即
f(x)=∏i=0i<n(x+i)=∑i=1i≤naixi
现在其实可以很简单地求出后n项的乘积
g(x)=∏i=ni<2n(x+i)
g(x)=i=1∑i≤nai(x+n)i
由二项式定理得
=i=1∑i≤naij=0∑j≤i(ji)ni−jxj
=i=1∑i≤nj=0∑j≤i(ji)ni−jaixj
=i=1∑i≤nj=0∑j≤i((i−j)!ni−j)(ai∗i!)(j!xj)
这就是个裸的卷积了。
所以可以算出这部分,得到
g(x)再乘上之前递归得到的
f(x)就成功做到倍增了。
注意:当n为奇数时,要向下取整,最后再
O(n)转移一次。
例题
2019雅礼集训permutation