营业日志 2020.12.25 求斯特林数的一些其他复杂度

大家圣诞节快乐……


我们认为以下几种问题及其复杂度在当下是已经基本普及的。

常规 行 S1

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 [ n k ] {n\brack k} [kn]

理论基础:多项式平移(或称泰勒展开)

实现:约等于两次长为 n n n 的多项式乘法。 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

常规 行 S2

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 { n k } {n\brace k} {kn}

理论基础:斯特林数的容斥公式

实现:一次长为 n n n 的多项式乘法。 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

常规 列 S1

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 [ m + k m ] {m+k\brack m} [mm+k]

理论基础:EGF

实现:多项式快速幂。 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

常规 列 S2

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 { m + k m } {m+k\brace m} {mm+k}

理论基础:EGF

实现:多项式快速幂。 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

常规 单点 S2

计算 { m n } {m\brace n} {nm}

理论基础:斯特林数的容斥公式

实现: Θ ( n log ⁡ n m ) \Theta(n\log_n m) Θ(nlognm)


行前缀 S2

对于 0 ≤ k ≤ m 0\le k\le m 0km,计算所有 { n k } {n\brace k} {kn}

实现: Θ ( m log ⁡ m n + m log ⁡ m ) \Theta(m\log_m n + m\log m) Θ(mlogmn+mlogm)

这实际上就是对发现前缀只需要把朴素算法的卷积截短一点,没什么太多意思。


我们可以通过拉格朗日反演来算一些特殊位置的点值。

行后缀 S1

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 [ m m − k ] {m\brack m-k} [mkm]

我们使用拉格朗日反演公式。令 F ( x ) = ln ⁡ 1 1 − x , G ( x ) = 1 − e − x F(x) = \ln \frac 1{1-x}, G(x) = 1-\mathrm{e}^{-x} F(x)=ln1x1,G(x)=1ex。由复合逆性质可得反演公式

m [ x m ] F m − k = ( m − k ) [ x − ( m − k ) ] G − m m [ x m ] ( ln ⁡ 1 1 − x ) m − k = ( m − k ) [ x k ] ( x 1 − e − x ) m [ m m − k ] = ( m − 1 ) ! ( m − k − 1 ) ! [ x k ] ( x 1 − e − x ) m \begin{aligned} m[x^m]F^{m-k}&=(m-k)[x^{-(m-k)}]G^{-m}\\ m[x^m]\left(\ln \frac 1{1-x}\right)^{m-k} &= (m-k)[x^k] \left(\frac x{1-\mathrm e^{-x}}\right)^m\\ {m\brack m-k} &= \frac{(m-1)!}{(m-k-1)!}[x^k] \left(\frac x{1-\mathrm e^{-x}}\right)^m \end{aligned} m[xm]Fmkm[xm](ln1x1)mk[mkm]=(mk)[x(mk)]Gm=(mk)[xk](1exx)m=(mk1)!(m1)![xk](1exx)m

行后缀 S2

我们令 F ( x ) = e x − 1 , G ( x ) = ln ⁡ ( 1 + x ) F(x)=\mathrm e^x-1, G(x)=\ln (1+x) F(x)=ex1,G(x)=ln(1+x),可得

{ m m − k } = ( m − 1 ) ! ( m − k − 1 ) ! [ x k ] ( x ln ⁡ ( 1 + x ) ) m {m\brace m-k} = \frac{(m-1)!}{(m-k-1)!}[x^k] \left(\frac x{\ln(1+x)}\right)^m {mkm}=(mk1)!(m1)![xk](ln(1+x)x)m

因此二者都可以通过多项式快速幂在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间计算。


但是 行后缀 S1 还有常数更小的求法。

行后缀 S1

由于第一类斯特林数的一行有一个简单的表达方法,因此我们可以发现求后缀无非是求

∏ i = 0 m ( 1 + i x ) \prod_{i=0}^m (1+ix) i=0m(1+ix)

的前 n n n 项,通过积和转换,对其取 ln ⁡ \ln ln,我们只需要对每个 1 ≤ k ≤ n 1\le k\le n 1kn,求出 k k k 次幂和。通过对伯努利数的预处理,这可以在常数较小的 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间解决。


事实上,还有一些其他奇怪的复杂度。比如和模数是不大的质数 p p p 相关的系列。

小质数 单点 S1

计算 [ m n ] {m \brack n} [nm]。同余质数 p > m p > m p>m

实现: Θ ( p ) \Theta(p) Θ(p)

这一算法的要点在于注意到我们可以直接考虑行 OGF x n ‾ = x ( x + 1 ) ⋯ ( x + n − 1 ) x^{\overline n} = x (x + 1) \cdots (x + n - 1) xn=x(x+1)(x+n1) 在所有位置的点值可以通过前缀积优化复杂度计算出,之后通过计算单点的 IDFT 值做到严格线性。即

IDFT ⁡ [ A ] j = 1 p − 1 ∑ k A k g − j k \operatorname{IDFT} [A]_j = \frac 1{p-1} \sum_k A_kg^{-jk} IDFT[A]j=p11kAkgjk

小质数 远处 单点 S1

计算 [ m n ] {m \brack n} [nm]。同余质数 p p p

实现: Θ ( p + log ⁡ p m ) + \Theta(p + \log_p m) + Θ(p+logpm)+ 进制转换。

注意到 x p ‾ ≡ x p − x x^{\overline p} \equiv x^p-x xpxpx 和 Lucas 定理 f ( x ) p ≡ f ( x p ) f(x)^p \equiv f(x^p) f(x)pf(xp),我们可以把计算需要的 m , n m,n m,n 降下来。


通过一点变体,我们可以以更小的常数计算第二类斯特林数的列。

改良 列 S2

对于 0 ≤ k ≤ n 0\le k\le n 0kn,计算所有 { m + k m } {m+k\brace m} {mm+k}

实现: Θ ( n log ⁡ m ) \Theta(n\log m) Θ(nlogm)

我们可以发现它的 OGF 实际上就是 1 ( 1 − x ) ( 1 − 2 x ) ⋯ ( 1 − m x ) \frac1{(1-x)(1-2x) \cdots (1-mx)} (1x)(12x)(1mx)1,其中分母就是第一类斯特林数的带符号倒转。所以 ∏ 1 ≤ k ≤ m ( 1 − k x ) \prod_{1\le k\le m} (1-kx) 1km(1kx) 是可以在 Θ ( m log ⁡ m ) \Theta(m\log m) Θ(mlogm) 时间内计算的。

接下来我们要注意到,对于 n n n 次多项式 f f f 商一个 m m m 次多项式 g g g,可以在 Θ ( n log ⁡ m ) \Theta(n\log m) Θ(nlogm) 时间内完成。我们可以每次 Θ ( m log ⁡ m ) \Theta(m\log m) Θ(mlogm) 求出这个商的前 m m m 项,设其为 h h h,那么考虑 f ( x ) / g ( x ) − h ( x ) f(x)/g(x)-h(x) f(x)/g(x)h(x) 就只改变了前 m m m 项,而其 = ( f ( x ) − g ( x ) h ( x ) ) / g ( x ) =(f(x)-g(x)h(x))/g(x) =(f(x)g(x)h(x))/g(x),其中分子的前 m m m 项为 0 0 0,我们就可以开始算下一组了。复杂度即为 Θ ( ( n / m ) ⋅ m log ⁡ m ) = Θ ( n log ⁡ m ) \Theta((n/m) \cdot m\log m) = \Theta(n\log m) Θ((n/m)mlogm)=Θ(nlogm)


事实上,第一类斯特林数的一行前缀也是可以优化的。但注意到 [ n 1 ] = ( n − 1 ) ! {n \brack 1}=(n-1)! [1n]=(n1)!,所以目前的技术要带 Ω ( n log ⁡ n ) \Omega(\sqrt n \log n) Ω(n logn) 了。

行前缀 S1

对于 0 ≤ k ≤ m 0\le k\le m 0km,计算所有 [ n k ] {n\brack k} [kn]

实现: Θ ( min ⁡ { m n log ⁡ n , n log ⁡ n } ) \Theta \left(\min \left\{m\sqrt n \log n, n\log n \right\}\right) Θ(min{mn logn,nlogn})

先粗略分析指数。

考虑设大小 B B B f y ( x ) = ∏ i = 0 B − 1 ( x + y + i ) f_y(x) = \prod_{i=0}^{B-1} (x+y+i) fy(x)=i=0B1(x+y+i),我们维护出 f 0 , f B , … , f ( n / B ) ⋅ B f_0,f_B,\dots,f_{(n/B) \cdot B} f0,fB,,f(n/B)B 关于 y y y 的点值表示。此时的多项式次数是 D = min ⁡ ( B , m ) D=\min(B, m) D=min(B,m),维护其的复杂度约为 O ~ ( D ( B + n / B ) ) \tilde O(D(B+n/B)) O~(D(B+n/B))

接下来需要将它们都乘起来。

D = m D=m D=m,那么接下来无非是 Θ ( n / B ) \Theta(n/B) Θ(n/B) m m m 次多项式乘法。复杂度为 Θ ( n m / B log ⁡ n ) \Theta(nm/B\log n) Θ(nm/Blogn),总和前者,总共复杂度为 O ~ ( m ( B + n / B ) ) \tilde O(m(B + n/B)) O~(m(B+n/B))。由于此时 B ≥ m B\ge m Bm,可在 m ≤ n m\le \sqrt n mn 时取到 O ~ ( m n ) \tilde O(m\sqrt n) O~(mn ),在 m > n m>\sqrt n m>n 时取到 O ~ ( m 2 ) \tilde O(m^2) O~(m2)

D = B D=B D=B,那么接下来等价于 Θ ( n / m ) \Theta(n/m) Θ(n/m) 轮的 m m m 次多项式乘法,那已经消耗了 O ~ ( n ) \tilde O(n) O~(n) 的时间,而带回前面的复杂度也有 O ~ ( B 2 + n ) \tilde O(B^2+n) O~(B2+n),因此不如朴素算法来的优!

可见,这种方法只有 m ≤ n m\le \sqrt n mn 的时候才是优秀的,注意到该方法在前面分块的部分可以通过经典的拉格朗日插值 + + + 倍增做到一个 log ⁡ \log log,因此整个算法的复杂度为 Θ ( m n log ⁡ n ) \Theta(m\sqrt n \log n) Θ(mn logn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值