之前在多项式里面讲过这个...不过感觉很不严谨啊。现在我们就来严谨的说明一波这个科技到底是怎么来的。
常系数齐次线性递推是指这样一个问题,给你一个数\(k\),接着对于\(i=1,2,...,k\),给出\(a_i\),代表递推的系数。再对于\(i=0,1,2,...,k-1\),给出\(f_i\)作为初始值,对于\(i\geq k\),数列\(f\)满足:
\[f_i=\sum_{j=1}^k a_j*f_{i-j}\]
最后给你一个数\(n\),需要求出\(f_n\)。\(n\)的范围很大。
在\(k\)比较小的时候,显然可以直接用矩阵快速幂来解决,转移矩阵如下:
\[ A=\left[ \begin{matrix} 0 & 1 & 0 & 0 & \cdots & 0 \\ 0 & 0 & 1 & 0 & \cdots & 0 \\ 0 & 0 & 0 & 1 & \cdots & 0 \\ 0 & 0 & 0 & 0 & \cdots & 0 \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ a_1 & a_2 & a_3 & a_4 & \cdots & a_k \end{matrix} \right] \]
如此一来,如果向量\(v=(f_i,f_{i+1},\cdots,f_{i+k-1})^T\),那么\(Av=(f_{i+1},f_{i+2},\cdots,f_{i+k})^T\),于是只要计算\(A^n\)即可,复杂度\(O(k^3\log n)\)。
但是如果\(k=10^3\),甚至\(k=10^5\),那么就无法使用矩阵快速幂了。我们来思考一下怎么样让线性递推更快。
为了方便,我们设向量\(\widehat v=(f_0,f_1,...,f_{k-1})\)。
我们考虑假设我们能够构造一个以矩阵为参数的多项式\(g\),满足:
\[\sum_{i=0}^kg_iA^i=0\]
那么显然我们可以把\(A^n\)用\(A^0,A^1,...,A^{k-1}\)线性表示出来——我们只需要计算\(A^n\bmod g\)即可,此处的取模应为多项式取模,假设取模以后得到的多项式为\(r\),于是我们有:
\[A^n=\sum_{i=0}^{k-1}r_iA^i\]
但是实际上我们不需要保留矩阵,我们只是想知道\((A^n\widehat v)_0\),因此这个式子实际上可以转化为:
\[(A^n\widehat v)_0=\sum_{i=0}^{k-1}r_i(A^i\widehat v)_0\]
而对于任意的\(i\),我们有\((A^i\widehat v)_0=f_i\),因此:
\[f_n=\sum_{i=0}^{k-1}r_if_i\]
于是我们只要求\(x^n\bmod g\),再将前\(k\)项已知的值代入即可计算,复杂度\(O(k\log k\log n)\)。
说得好听,那\(g\)到底该怎么求呢?
前方大量线性代数和数学证明出没。
为了方便,现在起我们在没有说明的情况下,默认矩阵的规模为\(n\times n\)。
引理\(1\):对于任意一个满秩的矩阵\(A\),复数域内恰好存在\(n\)个数\(\lambda\),满足\(\det(\lambda I-A)=0\)。
证明:恰好存在\(n\)个\(\lambda\)是很容易证明的,考虑将\(\det(\lambda I-A)\)看做一个以\(\lambda\)为参数的多项式,显然它是一个\(n+1\)次多项式,那么它在复数域内应该有\(n\)个根,同时要注意这里可能会有重根,但实际上这是没有关系的,不过我感觉具体的证明有点繁琐,所以就不放在这里了。一个比较直观的理解是你可以对输入进行很小的随机扰动使其没有重根,这不影响我们接下来的证明。
引理\(2\):对于某个满足\(\det(\lambda I-A)=0\)的\(\lambda\),存在一个对应的非零向量\(v\),使得\((\lambda I-A)v=0\)。并且对于所有\(n\)个\(\lambda\),他们对应的\(n\)个\(v\)是线性无关的。
证明:我们先来证明这样的\(v\)是存在的。我们求\(v\)的过程其实就等价于解\((\lambda I-A)v=0\)这个线性方程组,然而这个矩阵的行列式为\(0\)因此它是不满秩的,这意味着这个方程一定存在多解。如此一来,零向量就不可能是它的唯一解,因此我们一定可以找到这样的一个非零向量\(v\)。
接着,我们再来证明任意一对\(v\)不可能线性相关,注意这不代表\(n\)个\(v\)是线性无关的,因此这只是一个子问题。采用反证法,我们假设存在\(\lambda_1\),\(\lambda_2\),使得\((\lambda_1 I-A)v=0\)且\((\lambda_2 I-A)=0\),则我们有:
\[(\lambda_1 I-A)v-(\lambda_2 I-A)v=0\]
等价于:
\[(\lambda_1 I-\lambda_2 I)v=(\lambda_1-\lambda_2)Iv=0\]
因为\(\lambda_1\neq \lambda_2\),因此在两边除以\(\lambda_1-\lambda_2\),得到:
\[Iv=0\]
而\(Iv=v\),这就推出了\(v\)是零向量。然而\(v\)不是零向量,于是这就与前提矛盾,于是得证。
最后来证明\(n\)个\(v\)都是线性无关的。采用反证法,不失一般性,我们假设:
\[v_n=\sum_{i=1}^{n-1}k_iv_i\]
其中\(k_i\)为某特定常数。因为任意\((\lambda I-A)v=0\),于是我们有:
\[(\lambda_n I-A)v_n-\sum_{i=1}^{n-1}\Big((\lambda_i I-A)k_iv_i\Big)=0\]
再推导一下:
\[\lambda_n Iv_n-\sum_{i=1}^{n-1}\Big(\lambda_i Ik_iv_i\Big)+A(\sum_{i=1}^{n-1}k_iv_i)-Av_n=0\]
由于\(v_n=\sum_{i=1}^{n-1}k_iv_i\),后两项可以抵消,再将第一项转化一下,得:
\[\sum_{i=1}^{n-1}\Big(\lambda_n Ik_iv_i\Big)-\sum_{i=1}^{n-1}\Big(\lambda_i Ik_iv_i\Big)=\sum_{i=1}^{n-1}\Big((\lambda_n-\lambda_i) Ik_iv_i\Big)=0\]
由于\(Iv=v\),因此我们消去单位矩阵,得到:
\[\sum_{i=1}^{n-1}\Big((\lambda_n-\lambda_i)k_iv_i\Big)=0\]
于是我们得到了前\(n-1\)个向量也是线性相关的,以此类推,我们可以推到前\(2\)个向量也是线性相关的,然而这和我们之前证明出的结论矛盾,于是推翻了假设。我们证明了\(n\)个\(v\)是线性无关的。
引理\(3\):\(\prod_{i=1}^n(\lambda_i I-A)=0\)。
证明:我们不妨证明这个矩阵乘以任意向量都为\(0\),这和它是零矩阵是等价的(比较显然)。我们已知\(n\)个\(v_i\)都是线性无关的,那么对于任意向量\(\widehat v\),它一定可以表示为\(\sum_{i=1}^n k_iv_i\),其中\(k_i\)表示某一特定的常数。于是我们得到:
\[\Big(\prod_{i=1}^n(\lambda_i I-A)\Big)\widehat v=\sum_{i=1}^n\bigg(k_i\Big(\prod_{i=1}^n(\lambda_i I-A)\Big)v_i\bigg)\]
我们只需要证明任意\(\Big(\prod_{i=1}^n(\lambda_i I-A)\Big)v=0\)即可,考虑这个\(\prod\)的顺序是可以交换的,因为\((\lambda_1 I-A)(\lambda_2 I-A)=\lambda_1\lambda_2I-\lambda_1 A-\lambda_2A+A^2=(\lambda_2 I-A)(\lambda_1 I-A)\)。那么不妨考虑将与\(v\)对应的\((\lambda I-A)\)放到最后,先与\(v\)相乘,于是就得到了零向量,零向量乘以任意矩阵都会得到零向量,于是就证明了引理。
通过这三个引理,我们再进行深一步的思考。其实我们我们已经得到了一个满足条件的\(g\)(把\(A\)看作未知数):
\[\prod_{i=1}^n(\lambda_i I -A)\]
然而直接求解需要我们求出所有的特征值\(\lambda\),这很不可行。不妨来考虑这个多项式的下面两个特点:
\(1\)、这是一个\(n+1\)次的多项式。
\(2\)、可以很方便的求出其所有零点,即\(\lambda_1\)、\(\lambda_2\)、\(\cdots\)、\(\lambda_n\)。
同时我们可以知道我们只要找到一个满足上述条件的多项式,则这个多项式一定和\(\prod_{i=1}^n(\lambda_i I -A)\)相等。
仔细思考一下有没有什么之前提到的多项式满足这个条件。
有没有电光一闪的感觉?
\[\det(\lambda I-A)\]
没错就是它,次数界相同,零点也完全相同,只不过未知数换成了\(\lambda\)而已。
至此我们完成了我们的证明,\(\det(\lambda I-A)\)就是合法的满足\(g(A)=0\)的多项式\(g\)。
最后我们来回头解决线性递推问题。考虑手膜\(\lambda I-A\)的行列式多项式:
\[ \lambda I-A=\left[ \begin{matrix} \lambda & -1 & 0 & 0 & \cdots & 0 \\ 0 & \lambda & -1 & 0 & \cdots & 0 \\ 0 & 0 & \lambda & -1 & \cdots & 0 \\ 0 & 0 & 0 & \lambda & \cdots & 0 \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ -a_1 & -a_2 & -a_3 & -a_4 & \cdots & \lambda-a_k \end{matrix} \right] \]
显然只有最后一行需要变换,稍微手推一下,发现最后一行最后一个数最终就是:
\[\lambda-\sum_{i=1}^k\frac{a_i}{\lambda^{k-i}}\]
接着需要乘以\(\lambda^{k-1}\)得到最终的行列式,就是:
\[\lambda^k-\sum_{i=1}^ka_i*\lambda^{i-1}\]
其实结论还是非常简单的...
参考链接:shadowice1984的博客 感谢这篇文章让我了解了这个黑科技。