对于满足
a n = ∑ i = 1 k c i a n − i + f ( n ) a_n=\sum_{i=1}^{k}c_ia_{n-i}+f(n) an=i=1∑kcian−i+f(n)
一类的递推关系(其中 c , k c,k c,k 为常数),我们称之为常系数线性递推关系。
只要给定 a 0 , a 1 , … , a k − 1 a_0,a_1,\dots,a_{k-1} a0,a1,…,ak−1 以及 c 1 , c 2 , … , c k c_1,c_2,\dots,c_k c1,c2,…,ck 以及 f ( n ) f(n) f(n) ,我们就能求出 a a a 的任意一项。
这个问题的一般形式是不能快速求解的,比如令 f ( n ) = ln n f(n)=\ln n f(n)=lnn 。但有一些特殊形式我们可以快速求解。我们先从齐次常系数线性递推关系来研究。
齐次常系数线性递推关系即 f ( n ) = 0 f(n)=0 f(n)=0 的情况,此时 a n = ∑ i = 1 k c i a n − i a_n=\sum_{i=1}^{k}c_ia_{n-i} an=∑i=1kcian−i 。
这看起来像线性变换,因此考虑从线性变换的角度解决这个问题。
我们构造初始向量
x ⃗ = [ a k − 1 a k − 2 ⋮ a 1 a 0 ] \vec x= \left[ \begin{matrix} a_{k-1} \\ a_{k-2} \\ \vdots \\ a_1 \\ a_0 \\ \end{matrix} \right] x=⎣⎢⎢⎢⎢⎢⎡ak−1ak−2⋮a1a0⎦⎥⎥⎥⎥⎥⎤
以及转移矩阵
A = [ c 1 c 2 ⋯ c k − 2 c k − 1 c k 1 0 ⋯ 0 0 0 0 1 ⋯ 0 0 0 ⋮ ⋮ ⋱ ⋮ ⋮ ⋮ 0 0 ⋯ 1 0 0 0 0 ⋯ 0 1 0 ] A= \left[ \begin{matrix} c_1 &c_2 &\cdots &c_{k-2} &c_{k-1} & c_k\\ 1 & 0 &\cdots & 0 & 0 & 0 \\ 0 & 1 &\cdots & 0 & 0 & 0 \\ \vdots &\vdots & \ddots &\vdots &\vdots &\vdots \\ 0 & 0 &\cdots & 1 & 0 & 0 \\ 0 & 0 &\cdots & 0 & 1 & 0 \\ \end{matrix} \right] A=⎣⎢⎢⎢⎢⎢⎢⎢⎡c110⋮00c201⋮00⋯⋯⋯⋱⋯⋯ck−200⋮10ck−100⋮01ck00⋮00⎦⎥⎥⎥⎥⎥⎥⎥⎤
于是
A n ⋅ x ⃗ = [ a n + k − 1 a n + k − 2 ⋮ a n + 1 a n ] A^n\cdot \vec x= \left[ \begin{matrix} a_{n+k-1}\\ a_{n+k-2} \\ \vdots \\ a_{n+1}\\ a_n\\ \end{matrix} \right] An⋅x=⎣⎢⎢⎢⎢⎢⎡an+k−1an+k−2⋮an+1an⎦⎥⎥⎥⎥⎥⎤
这样我们就可以用矩阵快速幂来求 a n a_n an 了,复杂度 O ( k 3 log n ) O(k^3\log n) O(k3logn) 。
但这个复杂度依然不够优秀,考虑从线性代数的角度切入。
事实上,我们可以把 A n A^n An 表示为 A 0 , A 1 , ⋯   , A k − 1 A^0,A^1,\cdots,A^{k-1} A0,A1,⋯,Ak−1 的线性组合,并且我们有:
A n = ∑ i = 1 k c i A n − i A^{n}=\sum_{i=1}^{k} c_iA^{n-i} An=i=1∑kciAn−i
为什么呢?
我们可以从 C a y l a y − C a m i l t o n Caylay-Camilton Caylay−Camilton 定理1来考虑:
对于矩阵 A A A 的特征多项式 f ( λ ) = det ∣ λ I − A ∣ f( \lambda )=\det \left| \lambda I-A\right| f(λ)=det∣λI−A∣ ,我们有 f ( A ) = 0 f(A)=0 f(A)=0 。
而对于上述转移矩阵,我们有:
f ( λ ) = λ k − ∑ i = 1 k c i λ n − i f(\lambda)=\lambda ^k-\sum_{i=1}^{k}c_i \lambda ^{n-i} f(λ)=λk−i=1∑kciλn−i
将 A A A 代入上式即可。
当然我们也可以从其他角度考虑。
A n ⋅ x ⃗ = [ a n + k − 1 a n + k − 2 ⋮ a n + 1 a n ] A^{n}\cdot \vec x= \begin{bmatrix} a_{n+k-1}\\ a_{n+k-2} \\ \vdots \\ a_{n+1}\\ a_n\\ \end{bmatrix} An⋅x=⎣⎢⎢⎢⎢⎢⎡an+k−1an+k−2⋮an+1an⎦⎥⎥⎥⎥⎥⎤
∑ i = 1 k c i A n − i ⋅ x ⃗ = [ ∑ i = 1 k c i a n − i + k − 1 ∑ i = 1 k c i a n − i + k − 2 ⋮ ∑ i = 1 k c i a n − i + 1 ∑ i = 1 k c i a n − i ] = [ a n + k − 1 a n + k − 2 ⋮ a n + 1 a n ] = A n ⋅ x ⃗ \sum_{i=1}^{k} c_iA^{n-i}\cdot \vec x= \begin{bmatrix} \sum_{i=1}^kc_ia_{n-i+k-1}\\\\ \sum_{i=1}^kc_ia_{n-i+k-2}\\\\ \vdots \\\\ \sum_{i=1}^kc_ia_{n-i+1}\\\\ \sum_{i=1}^kc_ia_{n-i}\\\\ \end{bmatrix}= \begin{bmatrix} a_{n+k-1}\\\\ a_{n+k-2} \\\\ \vdots \\\\ a_{n+1}\\\\ a_n\\\\ \end{bmatrix}= A^{n}\cdot \vec x i=1∑kciAn−i⋅x=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡∑i=1kcian−i+k−1∑i=1kcian−i+k−2⋮∑i=1kcian−i+1∑i=1kcian−i⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡an+k−1an+k−2⋮an+1an⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤=An⋅x
也即:
( A n − ∑ i = 1 k c i A n − i ) ⋅ x ⃗ = 0 (A^{n}-\sum_{i=1}^{k} c_iA^{n-i})\cdot \vec x=0 (An−i=1∑kciAn−i)⋅x=0
由于任意向量 x ⃗ \vec x x 都满足这个关系,因此我们就得到了 A n − ∑ i = 1 k c i A n − i = 0 A^{n}-\sum_{i=1}^{k} c_iA^{n-i}=0 An−∑i=1kciAn−i=0 。
取 n = k n=k n=k 就有 f ( A ) = 0 f(A)=0 f(A)=0 。
无论如何,有了上述关系,我们只要求出 λ n   m o d   f ( λ ) \lambda ^n \bmod f(\lambda) λnmodf(λ) 即可。
设 g ( λ ) = λ n   m o d   f ( λ ) g(\lambda) =\lambda^n \bmod f(\lambda) g(λ)=λnmodf(λ) ,则 A n = f ( A ) P ( A ) + g ( A ) = 0 ⋅ P ( A ) + g ( A ) = g ( A ) A^n=f(A)P(A)+g(A)=0\cdot P(A)+g(A)=g(A) An=f(A)P(A)+g(A)=0⋅P(A)+g(A)=g(A) 。
再设
g ( λ ) = ∑ i = 0 k − 1 h i λ i g(\lambda)=\sum_{i=0}^{k-1}h_i\lambda^i g(λ)=i=0∑k−1hiλi
则
A n ⋅ x ⃗ = g ( A ) ⋅ x ⃗ = ∑ i = 0 k − 1 h i A i ⋅ x ⃗ = [ ∑ i = 0 k − 1 h i a k − 1 + i ∑ i = 0 k − 1 h i a k − 2 + i ⋮ ∑ i = 0 k − 1 h i a 1 + i ∑ i = 0 k − 1 h i a i ] A^n\cdot \vec x= g(A)\cdot \vec x= \sum_{i=0}^{k-1}h_iA^i \cdot \vec x= \begin{bmatrix} \sum_{i=0}^{k-1}h_ia_{k-1+i}\\ \\ \sum_{i=0}^{k-1}h_ia_{k-2+i}\\ \\ \vdots \\ \\ \sum_{i=0}^{k-1}h_ia_{1+i}\\ \\ \sum_{i=0}^{k-1}h_ia_{i}\\ \\ \end{bmatrix} An⋅x=g(A)⋅x=i=0∑k−1hiAi⋅x=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡∑i=0k−1hiak−1+i∑i=0k−1hiak−2+i⋮∑i=0k−1hia1+i∑i=0k−1hiai⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
这实际上是一个卷积的形式。我们只要把 h h h 和 a a a 的前 l + k − 1 l+k-1 l+k−1 项做多项式乘法就能求出连续的 l l l 项,如果只要求出单项就只需计算 ∑ i = 0 k − 1 h i a i \sum_{i=0}^{k-1}h_ia_i ∑i=0k−1hiai。
求 g ( λ ) g(\lambda) g(λ) 我们可以用倍增+多项式取模的方式。
如果使用 F F T FFT FFT 那么总复杂度就是 O ( k log k log n ) O(k\log k\log n) O(klogklogn) ,暴力取模就是 O ( k 2 log n ) O(k^2\log n) O(k2logn) 。
以及还有一个问题:怎么求出 a a a 的前 l l l 项?暴力求是 O ( k l ) O(kl) O(kl) 的。
由于这是一个序列问题,要求的项数不多,我们考虑用生成函数法解决。
设
f ( x ) = ∑ i = 0 ∞ a i x i , C ( x ) = ∑ i = 1 k c i x i f(x)=\sum_{i=0}^{\infty}a_ix^i,C(x)=\sum_{i=1}^kc_ix^i f(x)=i=0∑∞aixi,C(x)=i=1∑kcixi
由于将 f , C f,C f,C 卷积在前 k k k 项是错误的,因此我们构造
g ( x ) = f ( x ) − f ( x ) C ( x ) ( m o d x k ) g(x)=f(x)-f(x)C(x) \pmod{x^k} g(x)=f(x)−f(x)C(x)(modxk)
于是我们有 f ( x ) = f ( x ) C ( x ) + g ( x ) f(x)=f(x)C(x)+g(x) f(x)=f(x)C(x)+g(x) 。
因此 f ( x ) = g ( x ) 1 − C ( x ) f(x)=\frac{g(x)} {1-C(x)} f(x)=1−C(x)g(x) 。
值得一提的是 1 − C ( x ) 1-C(x) 1−C(x) 和转移矩阵特征多项式的关系。以及逆推这个过程我们会发现:若序列 a a a 的生成函数满足 f ( x ) = g ( x ) 1 − C ( x ) f(x)=\frac{g(x)} {1-C(x)} f(x)=1−C(x)g(x) 且 deg g < deg C = k \deg g<\deg C=k degg<degC=k 且 C C C 的常数项为 0 0 0 (实际上不为 1 1 1 即可),我们就可以把该序列与一个 k k k 阶线性递推方程相对应,这一点对非齐次线性递推也同样适用。
于是我们就能在 O ( k log k log n ) O(k\log k\log n) O(klogklogn) 的时间内解决齐次常系数线性递推的求值问题了。
注:以下部分的一些多项式算法,在我的这一篇博文中均有给出解法。
我们现在已经掌握齐次线性递推关系的求值算法了。
现在来讨论 f ( n ) f(n) f(n) 为多项式函数的情况。
我们尝试用化归法转化为齐次线性线性递推关系求解。
我们知道:
a n = ∑ i = 1 k c i a n − i + f ( n ) a_n=\sum_{i=1}^{k}c_ia_{n-i}+f(n) an=i=1∑kcian−i+f(n)
a n − 1 = ∑ i = 1 k c i a n − 1 − i + f ( n − 1 ) a_{n-1}=\sum_{i=1}^{k}c_ia_{n-1-i}+f(n-1) an−1=i=1∑kcian−1−i+f(n−1)
a n − a n − 1 = ∑ i = 1 k c i a n − i − ∑ i = 1 k c i a n − 1 − i + f ( n ) − f ( n − 1 ) = ∑ i = 1 k c i a n − i − ∑ i = 1 k c i a n − 1 − i + f 1 ( n ) a_n-a_{n-1}=\sum_{i=1}^{k}c_ia_{n-i}-\sum_{i=1}^{k}c_ia_{n-1-i}+f(n)-f(n-1)=\sum_{i=1}^{k}c_ia_{n-i}-\sum_{i=1}^{k}c_ia_{n-1-i}+f_1(n) an−an−1=i=1∑kcian−i−i=1∑kcian−1−i+f(n)−f(n−1)=i=1∑kcian−i−i=1∑kcian−1−i+f1(n)
显然 deg f 1 = deg f − 1 \deg f_1=\deg f-1 degf1=degf−1 ,设 f f f 的次数为 m m m ,我们只需要对其进行 m + 1 m+1 m+1 次对减就能转化为齐次关系。
现在问题在于如何求出新的递推关系以及 a k , ⋯   , a m + k a_k,\cdots,a_{m+k} ak,⋯,am+k 。
求 a k , ⋯   , a m + k a_k,\cdots,a_{m+k} ak,⋯,am+k 的值我们可以仿照上面的生成函数法:
设
F ( x ) = ∑ i = 0 ∞ a i x i , C ( x ) = ∑ i = 1 k c i x i , G ( x ) = F ( x ) − F ( x ) C ( x ) ( m o d x k ) , H ( x ) = ∑ i = k ∞ f ( i ) x i F(x)=\sum_{i=0}^{\infty}a_ix^i,C(x)=\sum_{i=1}^kc_ix^i,G(x)=F(x)-F(x)C(x) \pmod{x^k},H(x)=\sum_{i=k}^{\infty} f(i)x^i F(x)=i=0∑∞aixi,C(x)=i=1∑kcixi,G(x)=F(x)−F(x)C(x)(modxk),H(x)=i=k∑∞f(i)xi
则 F ( x ) = F ( x ) C ( x ) + G ( x ) + H ( x ) , F ( x ) = G ( x ) + H ( x ) 1 − C ( x ) F(x)=F(x)C(x)+G(x)+H(x),F(x)=\frac{G(x)+H(x)} {1-C(x)} F(x)=F(x)C(x)+G(x)+H(x),F(x)=1−C(x)G(x)+H(x)
不过这样我们需要使用一次多点求值算法,复杂度 O ( m log 2 m ) O(m\log^2 m) O(mlog2m) 。
至于新的递推关系,由于对减的特点,设原递推关系的转移矩阵特征多项式为 f ( λ ) f(\lambda) f(λ) ,新的递推关系的转移矩阵的特征多项式就是 f ( λ ) ( x − 1 ) m + 1 f(\lambda)(x-1)^{m+1} f(λ)(x−1)m+1 ,这样就得到了新的递推关系式。
于是求解该问题的总复杂度为 O ( m log 2 m + ( m + k ) log ( m + k ) log n ) O(m\log^2 m+(m+k)\log (m+k)\log n) O(mlog2m+(m+k)log(m+k)logn) 。
实际上除了求 a 0 , a 1 , ⋯   , a m + k a_0,a_1,\cdots,a_{m+k} a0,a1,⋯,am+k 的值以外,我们仅需要求得 x n   m o d   f ( x ) ( x − 1 ) m + 1 x^n \bmod f(x)(x-1)^{m+1} xnmodf(x)(x−1)m+1 。
若 f ( x ) f(x) f(x) 与 ( x − 1 ) m + 1 (x-1)^{m+1} (x−1)m+1 互质,我们可以求出 x n   m o d   f ( x ) x^n \bmod f(x) xnmodf(x) ,再求出 x n   m o d   ( x − 1 ) m + 1 x^n \bmod (x-1)^{m+1} xnmod(x−1)m+1 ,最后使用中国剩余定理合并。不互质的话我们只需提取出 f ( x ) f(x) f(x) 中的 ( x − 1 ) (x-1) (x−1) 因式即可。
对于 x n   m o d   ( x − 1 ) m + 1 x^n \bmod (x-1)^{m+1} xnmod(x−1)m+1 ,如果我们使用倍增取模,那么复杂度就是 O ( m log m log n + k log k log n ) O(m\log m\log n+k\log k\log n) O(mlogmlogn+klogklogn) ,并没有真正的优化复杂度。
但显然由于所模函数的特殊性,我们可以快速取模。我们只要求出 f ( x + 1 )   m o d   x m + 1 f(x+1) \bmod x^{m+1} f(x+1)modxm+1 ,再代入 ( x − 1 ) (x-1) (x−1) 就能求出 f ( x )   m o d   ( x − 1 ) m + 1 f(x) \bmod (x-1)^{m+1} f(x)mod(x−1)m+1 。
由于被取模函数的特殊性甚至可以不需要用到多项式算法,而直接使用组合数学的方法 O ( m ) O(m) O(m) 算出。当然这不是重点。
根据中国剩余定理我们需要求解这样的方程:
f ( x ) P ( x ) + ( x − 1 ) m + 1 Q ( x ) = 1 f(x)P(x)+(x-1)^{m+1}Q(x)=1 f(x)P(x)+(x−1)m+1Q(x)=1
我们可以直接套用 e x g c d exgcd exgcd 算法,复杂度是 O ( ( m + k ) log ( m + k ) ) O((m+k)\log (m+k)) O((m+k)log(m+k)) ,但常数较大。
一个较好的做法是转化为 f ( x + 1 ) P ( x + 1 ) + x m + 1 Q ( x + 1 ) = 1 f(x+1)P(x+1)+x^{m+1}Q(x+1)=1 f(x+1)P(x+1)+xm+1Q(x+1)=1 。这样就是多项式求逆了。
求 F ( x + q ) F(x+q) F(x+q) 是一个经典的问题,可见于上文提到的另一篇博文。
求出 P ( x ) P(x) P(x) 之后,设 A ( x ) = x n   m o d   f ( x ) , B ( x ) = x n   m o d   ( x − 1 ) m + 1 A(x)= x^n \bmod f(x),B(x)=x^n \bmod (x-1)^{m+1} A(x)=xnmodf(x),B(x)=xnmod(x−1)m+1 ,那么就有:
x n ≡ A ( x ) ( x − 1 ) m + 1 Q ( x ) + B ( x ) f ( x ) P ( x ) ≡ A ( x ) ( 1 − f ( x ) P ( x ) ) + B ( x ) f ( x ) P ( x ) ( m o d f ( x ) ( x − 1 ) m + 1 ) x^n \equiv A(x)(x-1)^{m+1}Q(x)+B(x)f(x)P(x) \equiv A(x)(1-f(x)P(x))+B(x)f(x)P(x) \pmod {f(x)(x-1)^{m+1}} xn≡A(x)(x−1)m+1Q(x)+B(x)f(x)P(x)≡A(x)(1−f(x)P(x))+B(x)f(x)P(x)(modf(x)(x−1)m+1)
这样求解的总复杂度是 O ( m log 2 m + k log k log n ) O(m\log ^2 m+k\log k \log n) O(mlog2m+klogklogn) 。
对于
f ( n ) = ∑ i = 1 t F i ( n ) q i n f(n)=\sum_{i=1}^t F_i(n)q_i^n f(n)=i=1∑tFi(n)qin
其中 F i ( n ) F_i(n) Fi(n) 为多项式函数, q i q_i qi 两两不相等。
我们依然可以仿照上面的方式进行求值。
每次设新的数列 b n = a n q i n b_n=\frac {a_n} {q_i^n} bn=qinan 并逐次差分即可。
设 F i F_i Fi 的次数为 m i m_i mi ,总差分次数为 M = ∑ i = 1 t ( m i + 1 ) M=\sum\limits_{i=1}^t (m_i+1) M=i=1∑t(mi+1) ,由于每次消去一个多项式时其余多项式的次数并不会发生变化,因此我们最终会将其化为齐次的 k + M k+M k+M 阶方程。
考虑如何求解新递推关系的特征方程。
设我们上一次消去的函数为第 l l l 项即 F l ( n ) q l n F_l(n)q_l^n Fl(n)qln ,则新的序列 b n b_n bn 满足 b n = a n q l n b_n=\frac{a_n} {q_l^n} bn=qlnan 。
则 b n b_n bn 的递推方程的特征多项式:
( x k − ∑ i = 1 k c i q l i x n − i ) ∏ i = 1 l ( x − q i q l ) m i + 1 (x^k-\sum_{i=1}^{k}\frac{c_i}{q_l^i}x^{n-i})\prod_{i=1}^l(x-\frac{q_i} {q_l})^{m_i+1} (xk−i=1∑kqlicixn−i)i=1∏l(x−qlqi)mi+1
而此时的函数形式为
f ′ ( n ) = ∑ i = l + 1 t F i ′ ( n ) ( q i q l ) n f'(n)=\sum_{i=l+1}^t F_i'(n)(\frac{q_i} {q_l})^n f′(n)=i=l+1∑tFi′(n)(qlqi)n
且各多项式函数的次数不变。
这并不难推导出来。当我们需要消去 F l + 1 ′ F'_{l+1} Fl+1′ 时,新的序列为 b ′ ( n ) = b n q l + 1 n q l n = b n q l n q l + 1 = a n q l + 1 n b'(n)=\frac{b_n} {\frac{q_{l+1}^n}{q_l^n}}=b_n\frac{q_l^n} {q^{l+1}}=\frac{a_n} {q_{l+1}^n} b′(n)=qlnql+1nbn=bnql+1qln=ql+1nan ,则特征方程中每一个因式从高到低各项分别乘上 ( q l q l + 1 ) j (\frac{q_l} {q_{l+1}})^j (ql+1ql)j ,且所有 F i ′ ( n ) ( q i q l ) n F'_i(n)(\frac{q_i} {q_l})^n Fi′(n)(qlqi)n 乘上 q l n q l + 1 \frac{q_l^n} {q^{l+1}} ql+1qln ,变为 F i ′ ( n ) ( q i q l + 1 ) n F'_i(n)(\frac{q_i} {q_{l+1}})^n Fi′(n)(ql+1qi)n 。
此时 F l + 1 ′ F'_{l+1} Fl+1′ 的指数为 1 1 1 ,其余函数指数不为 1 1 1 ,差分 m l + 1 + 1 m_{l+1}+1 ml+1+1 次会导致特征多项式乘上 ( x − 1 ) m l + 1 + 1 (x-1)^{m_{l+1}+1} (x−1)ml+1+1 并消去 F l + 1 ′ F'_{l+1} Fl+1′,且其余函数的多项式次数不变。
归纳证明即可。
通过这个结论,我们可以推导出 a n a_n an 最终化为齐次递推方程后方程的特征多项式为
( x k − ∑ i = 1 k c i x n − i ) ∏ i = 1 t ( x − q i ) m i + 1 (x^k-\sum_{i=1}^{k}c_ix^{n-i})\prod_{i=1}^t(x-q_i)^{m_i+1} (xk−i=1∑kcixn−i)i=1∏t(x−qi)mi+1
我们依然可以用原来的方法计算 x n   m o d   ( x − q i ) m i + 1 x^n \bmod (x-q_i)^{m_i+1} xnmod(x−qi)mi+1 ,并用类似解同余方程的方法以及 e x g c d exgcd exgcd 算法合并,注意要使用分治合并的方法,最坏情况下复杂度为 O ( M log M log t ) O(M \log M\log t) O(MlogMlogt) 。
同时我们要求出 a a a 的 O ( k + M ) O(k+M) O(k+M) 项。使用生成函数法我们还是要求出每个函数的点值,单次求点值的复杂度为 O ( min { m i log 2 m i + M log m i , m i M } ) O( \min\{m_i\log^2 m_i+M\log m_i,m_iM\}) O(min{milog2mi+Mlogmi,miM}) ,(注意多项式求值也可以当做线性递推问题求连续点的点值),并且我们需要求 t t t 次。当 t t t 较小时复杂度是 O ( t M log M + M log 2 M ) O(tM\log M+M\log^2 M) O(tMlogM+Mlog2M) 的, t t t 较大时使用暴力求值法更优秀,复杂度为 O ( M 2 ) O(M^2) O(M2) 。
总复杂度 O ( min { t M log M + M log 2 M , M 2 } + k log k log n ) O(\min\{tM\log M+M\log^2 M,M^2\}+k\log k \log n) O(min{tMlogM+Mlog2M,M2}+klogklogn) 。
在上述算法中,最劣情况下复杂度含有一个 M 2 M^2 M2 ,显然是非常不优秀的。
考虑什么地方出现了问题。
显然瓶颈在于如何求 a k , a k + 1 , ⋯   , a k + M a_k,a_{k+1},\cdots,a_{k+M} ak,ak+1,⋯,ak+M ,而当 t t t 很大时也就是底数不同的指数函数过多时暴力求出点值用以表示序列的生成函数是不优秀的。
类似于序列 1 n + 2 n + ⋯ + m n 1^n+2^n+\cdots +m^n 1n+2n+⋯+mn 的生成函数为 ∑ i = 1 m 1 1 − i x \sum\limits_{i=1}^{m}\frac{1}{1-ix} i=1∑m1−ix1 ,显然可以使用分治 F F T FFT FFT 在 O ( m log 2 m ) O(m\log^2 m) O(mlog2m) 时间内求出,但是若是使用上面的点值法表示生成函数复杂度就会达到 m 2 m^2 m2 。
现在我们考虑如何快速求出序列的通项形如 a n = F ( n ) q n a_n=F(n)q^n an=F(n)qn 的生成函数。
首先我们依然可以设 b n = a n q n b_n=\frac{a_n} {q^n} bn=qnan 将该问题化归为求解 F ( n ) F(n) F(n) 的生成函数。
多项式生成函数问题在上文提到的博文中有给出解法,这里不再赘述。
对于线性递推式:
a n = ∑ i = 1 k c i a n − i + f ( n ) a_{n}=\sum_{i=1}^{k} c_ia_{n-i}+f(n) an=i=1∑kcian−i+f(n)
f ( n ) = ∑ i = 1 t F i ( n ) q i n f(n)=\sum_{i=1}^t F_i(n)q_i^n f(n)=i=1∑tFi(n)qin
我们只需设 H ( x ) = ∑ i = k ∞ f ( i ) x i = x k ∑ i = 1 t G i ( x ) ( 1 − q i x ) m i + 1 H(x)=\sum_{i=k}^{\infty} f(i)x^i=x^k\sum_{i=1}^{t} \frac{G_i(x)} {(1-q_ix)^{m_i+1}} H(x)=i=k∑∞f(i)xi=xki=1∑t(1−qix)mi+1Gi(x)
即可。
只需 O ( ∑ i = 1 t m i log 2 m i ) O(\sum\limits_{i=1}^{t}m_i\log^2 m_i) O(i=1∑tmilog2mi) 求出每一个 G i G_i Gi 。
然后使用与上面使用生成函数法时一致的做法,即:
F ( x ) = G ( x ) + H ( x ) 1 − C ( x ) F(x)=\frac{G(x)+H(x)} {1-C(x)} F(x)=1−C(x)G(x)+H(x)
就可以求出 a k , a k + 1 , ⋯   , a M + k a_k,a_{k+1},\cdots,a_{M+k} ak,ak+1,⋯,aM+k 的值了。
类似的,依然有总复杂度为 O ( M log 2 M + k log k log n ) O(M\log^2 M+k\log k\log n) O(Mlog2M+klogklogn) 。
C a y l a y − C a m i l t o n Caylay-Camilton Caylay−Camilton 定理可以从线性代数的相关资料以及网络上找到证明。 ↩︎