第一类斯特林数
s 1 n m s1_n^m s1nm表示将 n n n个数放进 m m m个圆排列的方案数。
有一个显然的递推式:
s 1 n m = s 1 n − 1 m − 1 + ( n − 1 ) s 1 n − 1 m s1_n^m=s1_{n-1}^{m-1}+(n-1)s1_{n-1}^m s1nm=s1n−1m−1+(n−1)s1n−1m,对应的意义:要么第 n n n个单独构成一个新的圆排列,要么放在之前某个数的后面。
还有一种组合意义:一共进行 n n n次操作,第 i i i次可以添加跟第 1 1 1~ i − 1 i-1 i−1中任意一种物品相同的旧物品或者添加一种新物品,问最后一共有 m m m中不同物品的方案数,由此可以推出第一类斯特林数的生成函数:
∏ i = 0 n − 1 ( x + i ) \prod_{i=0}^{n-1}(x+i) ∏i=0n−1(x+i)
到这里就有两种挺明显的预处理斯特林数方法了:
- 如果要求出每一个 s 1 i j s1_i^j s1ij,可以用 O ( n m ) O(nm) O(nm)递推
- 如果只用求出每一个 s 1 a k , a s1_a^k,a s1ak,a为定值,可以上分治 f f t fft fft做到 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
但有些毒瘤出题人偏偏会卡你的分治 f f t fft fft,需要我们在更短的时间内求出某一行的值。
于是就有了下面的倍增算法:
假设我们已经求出了 f n ( x ) = ∏ i = 0 n − 1 ( x + i ) = ∑ i = 0 n a i x i f_n(x)=\prod_{i=0}^{n-1}(x+i)=\sum_{i=0}^na_ix^i fn(x)=∏i=0n−1(x+i)=∑i=0naix