线性递推与整式递推数列
线性递推与整式递推数列
本文主要摘录自 2019 年国家候选队论文集《两类递推数列的性质和应用》——钟子谦。
线性递推数列
定义
对于无限数列 ,和有限非空数列 ,若对于任意 ,有 ,则称 为 的线性递归式。特别的,若 ,称 为 的线性递推式。
我们称存在线性递推式的无限数列为线性递推数列。
对于有限数列,我们类似的定义线性递推式,称线性递推式的阶数,为其长度减一(上文中的 为 的阶数),称数列 阶数最小的线性递推式为 的最短线性递推式。
基本性质与判定
从生成函数的角度来看线性递归式,有结论:
对于无限数列 ,和有限非空数列 ,记两者的生成函数为 ,数列 为 的线性递归式等价于存在次数不超过 的多项式 ,满足 。
有限数列的情况仅需改成 。
结论的证明很显然,考虑其推论:
对于无限数列 ,记其生成函数为 , 为线性递推数列等价于存在常数项为 的多项式 和多项式 满足 。数列 的最短递推式阶数为所有的 对中 的最小可能值。
线性递推数列满足以下的封闭性:
- 线性递推数列乘常数仍是线性递推数列。
- 线性递推数列平移仍是线性递推数列。
- 两个线性递推数列相加仍是线性递推数列。
- 两个线性递推数列卷积仍是线性递推数列。
- 两个线性递推数列点乘仍是线性递推数列。
有关算法
求出数列的最短线性递推式
我们先考虑有限数列的情况。
一种简单的做法是高斯消元解出最短线性递推式,对于阶为 的有限数列来说复杂度 ,使用 Berlekamp-Massey(BM) 算法可以将复杂度降至 。(实际上其复杂度为 , 为最短线性递推式阶数。)
BM 会对数列 的每个前缀求出其最短线性递推式。
为了方便,定义新的递推系数的形式 :
。上文定义的阶数在新的形式下即为 。
按位考虑 的每一位,在递推出现错误时对系数进行调整,记 的最短线性递推式为 ,记 。
初始时 ,处理到 时有两种情况:
- 对 也成立,不需要调整,。
- 对 不成立,考虑进行调整。
记 。
若此时是第一次对递推式进行修改( 为第一个非 0 项),直接令 为 个 。
否则找到上一次对递推式修改的位置 ,考虑构造一个序列 ,满足: 且 。
那么我们令 即可。
一种可行的构造是 。
前缀 0 的个数为 ,最后一项的意思是将 乘上系数加在 后。
不难验证构造的正确性,我们还需说明构造的最小性。
引理:若 不是 的最短线性递推式,有:
考虑反证,假设 。设 。
那么 为 的最短递推式,矛盾。
回到我们上文给出的构造,当 不是 的最短递推式时,我们构造得到的 。
考虑我们归纳这样的 就是最短的,那么有 ,则 。故新的 。构造的最小性成立。
对于无限序列,若我们知道其最短递推式的长度 ,我们取其前 项跑 BM 就能得到其最短递推式。
实现很清新:
vec BM(int *a,int n){
int lst=-1,val=0;
vec F0,F1;F0.clear();F1.clear();
for(int i=0;i<=n;i++){
int del=a[i];
for(int j=0;j<F1.size();j++)del=sub(del-1ll*F1[j]*a[i-j-1]%mod);
if(del==0)continue;
if(lst==-1){lst=i,val=del;F0=F1;for(int j=0;j<=i;j++)F1.eb(0);continue;}
vec G;G.clear();
for(int j=1;j<=i-lst-1;j++)G.eb(0);
int w=1ll*del*power(val,mod-2)%mod;
G.eb(w);for(int j=0;j<F0.size();j++)G.eb(sub(-1ll*w*F0[j]%mod));
F0=F1;F1.resize(max(F1.size(),G.size()));
for(int j=0;j<G.size();j++)F1[j]=add(F1[j]+G[j]);
lst=i,val=del;
}
return F1;
}
求出一个线性递推数列的第 项
常系数齐次线性递推,运用 BM 得到线性递推式后,使用多项式取模以 或者 的复杂度求得数列第 项。
应用
求向量序列和矩阵序列的最短递推式
考虑如何求出 维行向量序列 的线性递推式。假设考虑在模 意义下随机一个 维列向量 ,转而计算 这个标量序列的最短线性递推式。
根据著名的 Schwartz-Zippel 引理,我们可以推导出至少有 的概率我们得到的线性递推式正确。
我们类似的求 的矩阵序列 的线性递推式,随机一个 维列向量 ,和一个 维行向量,计算 的线性递推式。我们有至少 的概率得到正确线性递推式。
求矩阵的最小多项式
定义 的矩阵 的最小多项式为次数最小的使得 的多项式 。
矩阵的最小多项式显然就是 的最短线性递推式,我们使用上文的方法求出矩阵序列的最短线性递推式即可。
具体的,我们可以在 的时间内将标量序列得到,对于稀疏矩阵,记 为矩阵中的非零元素个数,可以在 的时间内得到标量序列。
之后进行最劣 的 BM 即可。
优化动态规划
传统使用矩阵快速幂优化的 形式的动态规划复杂度为 。
由于 为线性递推向量序列,我们使用 BM 求出其线性递推式,再使用常系数齐次线性递推,可以做到 或者 。
解稀疏线性方程组
即求 。
考虑求得 的最短递推式 ,我们有 ,由于 最短,。在两边乘上 移项,可以得到 。
瓶颈在于求 ,若 中有 个非零元素,总时间复杂度 。
求稀疏矩阵行列式
注意到我们可以快速地求出稀疏矩阵的最小多项式,而当矩阵的每个特征值的几何重数均为一时最小多项式就是特征多项式。对于 阶矩阵,特征多项式的常数项乘上 即为行列式(因为行列式即全部特征值的乘积)。
由于我们所求的矩阵 不一定每个特征值的几何重数均为一,我们给它乘上一个随机的对角矩阵 ,可以证明 有至少 的概率满足性质,得到 后由于 , 容易计算,我们容易得到 的值。
求稀疏矩阵的秩
感觉没啥用啊,有点复杂,鸽着。
整式递推数列
介于笔者的高数水平一般,这个部分很多会省略证明过程。
定义
对于无限数列 和有限非空多项式列 ,若 非 且对于任意 ,有 ,则称 为数列 的整式递推式,称存在整式递推式的数列 为整式递推数列。
对于有限数列的定义类似。
显然,上述的线性递推数列是整式递推数列。
我们类比线性递推,定义整式递推式的阶数为 ,次数为 。
为了更好的描述整式递推数列的性质、连接生成函数,我们引入微分有限(D-finite)和代数形式幂级数(Algebraic)。
我们称一个形式幂级数 为微分有限的当且仅当存在多项式数列 ,满足 且 。
我们称一个形式幂级数 为代数形式幂级数当且仅当其在 上是代数的(即 为系数在 内的多项式方程的根)。
代数形式幂级数的定义类似于数域中代数数的定义,与其相对的为超越数。
举一些容易理解的例子,代数数:,超越数:。
基本性质与判定
记一个数列 的 OGF 为 ,那么 是整式递推数列当且仅当 微分有限。
下文我们考虑一种常见的生成函数——代数形式幂级数。我们可以证明代数形式幂级数都是微分有限的,不仅如此,我们有更强的结论:
代数形式幂级数 的微分 也是代数形式幂级数。
记 微分有限, 是代数的,有定义的( 有限或 常数项为 ) 微分有限。
与线性递推类似,整式递推数列也满足以下封闭性:
- 整式递推数列乘常数仍为整式递推数列。
- 整式递推数列平移仍为整式递推数列。
- 两个整式递推数列相加仍为整式递推数列。
- 两个整式递推数列卷积仍为整式递推数列。
- 两个整式递推数列点乘仍为整式递推数列。
有关算法
求出数列的整式递推式
一个暴力但实用的方法是将 个系数直接高斯消元,这里的阶数和次数都是一个预估值,取肯定比真正阶数与次数略大的值即可。
求出一个整式递推数列的第 项
记整式递推式的次数为 ,阶数为 ,那么我们直接递推,有暴力的 做法。
对于 远大于 的情形,存在一个 的做法。
当 为常数时,其复杂度为 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix