[线性代数学习笔记] 线性递推数列及 Berlekamp-Massey 算法的详细推导过程

线性递推数列

线性递推

对于无限数列 {a0,a1,...}\{a_0,a_1,...\}{a0,a1,...} 和有限非空数列 {r0,r1,...,rm−1}\{r_{0},r_1,...,r_{m-1}\}{r0,r1,...,rm1}

若对于任意 m−1≤nm-1\le nm1n ,有 ∑i=0m−1an−iri=0\sum_{i=0}^{m-1}a_{n-i}r_i=0i=0m1aniri=0 ,则称数列 rrr 为数列 aaa线性递归式

r0=1r_0=1r0=1,称数列 rrr 为数列 aaa线性递推式

称存在线性递推式的无限数列为线性递推数列

r0=1r_0=1r0=1 说明可以写成 an=−(an−1∗r1+an−2∗r2+...+an−m+1∗rm−1)a_n=-(a_{n-1}*r_1+a_{n-2}*r_2+...+a_{n-m+1}*r_{m-1})an=(an1r1+an2r2+...+anm+1rm1)

对于有限数列 {a0,a1,...an−1}\{a_0,a_1,...a_{n-1}\}{a0,a1,...an1} 和有限非空数列 {r0,r1,...,rm−1}\{r_{0},r_1,...,r_{m-1}\}{r0,r1,...,rm1}

若对于任意 m−1≤p≤nm-1\le p\le nm1pn ,有 ∑i=0m−1ap−iri=0\sum_{i=0}^{m-1}a_{p-i}r_i=0i=0m1apiri=0 ,则称数列 rrr 为数列 aaa线性递归式

r0=1r_0=1r0=1,称数列 rrr 为数列 aaa线性递推式

称这个线性递推式的阶数为它的长度 −1-11。(因为下标是从 000 开始的)

称数列 aaa 阶数最小的线性递推式为数列 aaa最短线性递推式

生成函数

对于有限数列 {a0,...,an−1}\{a_0,...,a_{n-1}\}{a0,...,an1},定义它的生成函数为多项式 A(x)=∑i=0n−1aixiA(x)=\sum_{i=0}^{n-1}a_ix^iA(x)=i=0n1aixi

对于无限数列 {a0,a1,...}\{a_0,a_1,...\}{a0,a1,...},定义它的生成函数为形式幂级数 A(x)=∑0∞aixiA(x)=\sum_{0}^∞a_ix^iA(x)=0aixi

对于无限数列 {a0,a1,...}\{a_0,a_1,...\}{a0,a1,...} 和有限非空数列 {r0,r1,...,rm−1}\{r_{0},r_1,...,r_{m-1}\}{r0,r1,...,rm1}

设数列 aaa 的生成函数为 AAA,数列 rrr 的生成函数为 RRR

数列 rrr 为数列 aaa 的线性递归式等价于存在次数不超过 m−2m-2m2 次的多项式 CCC,满足 AR+C=0AR+C=0AR+C=0

对于有限数列 {a0,a1,...,an−1}\{a_0,a_1,...,a_{n-1}\}{a0,a1,...,an1} 和有限非空数列 {r0,r1,...,rm−1}\{r_{0},r_1,...,r_{m-1}\}{r0,r1,...,rm1}

设数列 aaa 的生成函数为 AAA,数列 rrr 的生成函数为 RRR

数列 rrr 为数列 aaa 的线性递归式等价于存在次数不超过 m−2m-2m2 次的多项式 CCC,满足 AR+C≡0(modxn)AR+C\equiv 0\pmod {x^n}AR+C0(modxn)

Berlekamp-Massey

注意:上面的都是下标从 000 开始,这里的算法流程下标是从 111 开始的。

Berlekamp-Massey 算法是用来在 O(n2)O(n^2)O(n2) 的时间里求一个数列的最短线性递推式

方法思想是增量法

重申明确一下问题模型:给定 nnn 个元素的数列 a1,...ana_1,...a_na1,...an,求一个最短的数列 r1,...rmr_1,...r_mr1,...rm。要求满足 ∀m<i≤nai=∑j=1mai−jrj\forall_{m<i\le n}\ a_i=\sum_{j=1}^{m}a_{i-j}r_jm<in ai=j=1maijrj。要求在 O(n2)O(n^2)O(n2) 时间内解决。

注意1:这个递推的下标可以看作是一种卷积形式,相加和为一个“定值”,这有利于你快速理解下面的一些下标变换与对应。

注意2:这个条件只需要 >m>m>m 的下标做到,换言之如果被当成了 rrr 中的一个“基”,是不需要满足这个式子的,因为会有下标为负的情况。

注意3:ai=a[i]=a(i)a_i=a[i]=a(i)ai=a[i]=a(i) 只是表达方式不同。

假设递推式已经经过了 ttt 次更新,第 iii 次更新的递推式记为 r(i)r(i)r(i)这是一个多项式),长度为 m(i)m(i)m(i)。初始时,定义 r(0)=∅,m(0)=0r(0)=\empty,m(0)=0r(0)=,m(0)=0

一个一个考虑加入数列 aaa 中元素,现在即将加入 aia_iai。假设现在递推式长度为 m=m(t)m=m(t)m=m(t)

Δ(i)=ai−∑j=1ma[i−j]⋅r(i)[j]\Delta(i)=a_i-\sum_{j=1}^ma[i-j]·r(i)[j]Δ(i)=aij=1ma[ij]r(i)[j]

  • Δ(i)=0\Delta(i)=0Δ(i)=0,证明目前递推式仍然满足条件,合法不用修改,继续考虑加入下一个。

  • Δ(i)≠0\Delta(i)\neq 0Δ(i)=0。设 fail(t)=i\text{fail}(t)=ifail(t)=i,表示 r(t)r(t)r(t) 递推式第一次失效的位置在 iii

    • t=0t=0t=0

      意味着 aia_iai 前面的数都为 000。那么不管递推数列怎么配求和都是 000。显然只能将 iii 这个下标也被递推式包含。

      所以新的递推式直接就是 r(t+1)={0,0,...,0⏟i}r(t+1)=\{\underbrace{0,0,...,0}_i\}r(t+1)={i0,0,...,0}

      这样就不需要 aia_iai 满足上面求和的式子了,它已经作为递推式的一个“基”了。

    • t≠0t\ne 0t=0

      考虑构造一个递推式 RRR,满足 ∀∣R∣<k<i∑j=1∣R∣ak−jRj=0\forall_{|R|<k<i}\ \sum_{j=1}^{|R|}a_{k-j}R_j=0R<k<i j=1RakjRj=0∑j=1∣R∣ai−jRj=Δ(i)\sum_{j=1}^{|R|}a_{i-j}R_j=\Delta(i)j=1RaijRj=Δ(i)

      寻找之前某次失效的递推式,0≤p<t0\le p<t0p<t,显然这个递推式的失效位置为 fail(p)\text{fail}(p)fail(p)

      同时,设 ω=Δ(i)Δ(fail(p))\omega=\frac{\Delta(i)}{\Delta\big(\text{fail}(p)\big)}ω=Δ(fail(p))Δ(i),则 R={0,0,…,0⏟i−fail(p)−1,ω,−ω⋅r(p)[1],−ω⋅r(p)[2],...,−ω⋅r(p)[∣r(p)∣]}R=\{\underbrace{0,0,…,0}_{i-\text{fail}(p)-1},\omega,-\omega·r(p)[1],-\omega·r(p)[2],...,-\omega·r(p)\Big[\big|r(p)\big|\Big]\}R={ifail(p)10,0,,0,ω,ωr(p)[1],ωr(p)[2],...,ωr(p)[r(p)]}

      r(t+1)=r(t)+Rr(t+1)=r(t)+Rr(t+1)=r(t)+R 即可。(加法遵循多项式加法原则,即对位系数相加


      中场休息——请确保上面的下标之间关系理清楚了,再继续往下看正确性


      为什么这样是对的?理论解释不清楚,不妨眼见为实,我们直接带进去算。

      • 对于 aia_iai

        R[1,i−fail(p)−1]R[1,i-\text{fail}(p)-1]R[1,ifail(p)1] 都为 000,对应 a[i−1,fail(p)+1]a[i-1,\text{fail}(p)+1]a[i1,fail(p)+1] 相乘和为 000

        真正乘起来有值的是从 R[i−fail(p)]↔a[fail(p)]R\big[i-\text{fail}(p)\big]\leftrightarrow a\big[\text{fail}(p)\big]R[ifail(p)]a[fail(p)] 项开始的。

        并且后面对应相乘,r(p)[1]↔a[fail(p)−1],r(p)[2]↔a[fail(p)-2]......r(p)[1]\leftrightarrow a[\text{fail}(p)-1],r(p)[2]\leftrightarrow a[\text{fail(p)-2}]......r(p)[1]a[fail(p)1],r(p)[2]a[fail(p)-2]......

        等等!!!

        这相乘求和不就是第 ppp 个递推式失效的位置对应的表达式吗?转化一下即 =afail(p)−Δ(fail(p))=a_{\text{fail(p)}}-\Delta\big(fail(p)\big)=afail(p)Δ(fail(p))

        ⇒ω⋅afail(p)−ω⋅(afail(p)−Δ(fail(p)))=ω∗Δ(fail(p))=Δ(i)\Rightarrow \omega·a_{\text{fail(p)}}-\omega·\Big(a_{\text{fail(p)}}-\Delta\big(\text{fail}(p)\big)\Big)=\omega*\Delta\big(\text{fail}(p)\big)=\Delta(i)ωafail(p)ω(afail(p)Δ(fail(p)))=ωΔ(fail(p))=Δ(i)

        发现 RRRr(t)r(t)r(t) 失效的差距部分恰好补上了。

        由此可知 r(t+1)r(t+1)r(t+1)aia_iai 成立。

      • 对于 m≤k<im\le k<imk<i。其实推导与上面差不多。

        R[1,i−fail(p)−1]R[1,i-\text{fail}(p)-1]R[1,ifail(p)1] 都为 000,对应 a[k−1,k−i+fail(p)+1]a[k-1,k-i+\text{fail}(p)+1]a[k1,ki+fail(p)+1] 相乘和为 000

        真正乘起来有值的是从 R[i−fail(p)]↔a[k−i+fail(p)]R\big[i-\text{fail}(p)\big]\leftrightarrow a\big[k-i+\text{fail}(p)\big]R[ifail(p)]a[ki+fail(p)] 项开始的。

        并且后面对应相乘,r(p)[1]↔a[k−i+fail(p)−1],r(p)[2]↔a[k−i+fail(p)-2]......r(p)[1]\leftrightarrow a[k-i+\text{fail}(p)-1],r(p)[2]\leftrightarrow a[k-i+\text{fail(p)-2}]......r(p)[1]a[ki+fail(p)1],r(p)[2]a[ki+fail(p)-2]......

        转化一下即 =ak−i+fail(p)−Δ(k−i+fail(p))=a_{k-i+\text{fail}(p)}-\Delta(k-i+\text{fail}(p))=aki+fail(p)Δ(ki+fail(p))

        因为 k<ik<ik<i,所以 k−i+fail(p)<fail(p)k-i+\text{fail}(p)<\text{fail}(p)ki+fail(p)<fail(p)

        还记得 fail(p)\text{fail}(p)fail(p) 的定义吗?——是 r(p)r(p)r(p) 第一个失效的位置。换言之,在此位置之前 r(p)r(p)r(p) 都是成立的。

        所以 Δ(k−i+fail(p))=0\Delta(k-i+\text{fail}(p))=0Δ(ki+fail(p))=0

        ⇒ω⋅ak−i+fail(p)−ω⋅(ak−i+fail(p)−Δ(k−i+fail(p)))=ω∗Δ(k−i+fail(p))=0\Rightarrow \omega·a_{k-i+\text{fail(p)}}-\omega·\Big(a_{k-i+\text{fail(p)}}-\Delta\big(k-i+\text{fail}(p)\big)\Big)=\omega*\Delta\big(k-i+\text{fail}(p)\big)=0ωaki+fail(p)ω(aki+fail(p)Δ(ki+fail(p)))=ωΔ(ki+fail(p))=0

      综上,我们构造的这个 RRR 本质上只起到了对 aia_iai 补充 Δ(i)\Delta(i)Δ(i) 的效果,对于其余 kkk 的贡献都是 000

      这是利用了 r(p)r(p)r(p)1∼fail(p)−11\sim \text{fail}(p)-11fail(p)1 都满足关系,而在 fail(p)\text{fail}(p)fail(p) 相差 Δ(p)\Delta(p)Δ(p) 的性质。


      此外我们还希望递推式的长度越短越好,也就是说 max⁡(m(t),i−fail(p)+m(p))\max\big(m(t),i-\text{fail}(p)+m(p)\big)max(m(t),ifail(p)+m(p)) 最短。

      贪心地只需要动态维护最短的 i−fail(p)+m(p)i-\text{fail}(p)+m(p)ifail(p)+m(p),每次算出 r(t+1)r(t+1)r(t+1) 时都与之前的 r(p)r(p)r(p) 比一下谁更短即可。

一共递推 O(n)O(n)O(n) 次,每次修改 O(n)O(n)O(n) 次,时间复杂度为 O(n2)O(n^2)O(n2)

代码实现中,rrr 用的是 vector\text{vector}vector,下标从 000 开始,所以有些下标会与上面的推导略有差异。且不保证一定正确!!!

//std参考code
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define int long long
#define maxn 1005
int n, cnt;
int a[maxn], fail[maxn], delta[maxn];
vector < int > r[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 1;i <= n;i ++ )if( ! cnt ) {if( a[i] ) {fail[cnt ++] = i;delta[i] = a[i];r[cnt].resize( i, 0 );}continue;}else {fail[cnt] = i;delta[i] = a[i];for( int j = 0;j < r[cnt].size();j ++ ) ( delta[i] -= a[i - j - 1] * r[cnt][j] ) %= mod;if( ! delta[i] ) continue;// int len = 0x7f7f7f7f, p;int len = i - fail[cnt - 1] + r[cnt - 1].size(), p = cnt - 1;for( int j = 0;j < cnt;j ++ )if( i - fail[j] + r[j].size() < len )len = i - fail[j] + r[j].size(), p = j;int omega = delta[i] * qkpow( delta[fail[p]], mod - 2 ) % mod;r[cnt + 1] = r[cnt];cnt ++;while( r[cnt].size() < len ) r[cnt].push_back( 0 );( r[cnt][i - fail[p] - 1] += omega ) %= mod;for( int j = 0;j < r[p].size();j ++ )( r[cnt][i - fail[p] + j] -= omega * r[p][j] ) %= mod; }printf( "%lld\n", r[cnt].size() );for( int i : r[cnt] ) printf( "%lld ", ( i + mod ) % mod );return 0;
}
/*
Input 1
7
1 2 4 9 20 40 90
Output 1
4 
0 0 10 0Input 2 
18
2 4 8 16 32 64 128 256 512 2 4 8 16 32 64 128 256 512
Output 2 
0 0 0 0 0 0 0 0 1
*/

BM算法和线性递推的应用

当我们确信这个题是 矩阵加速 / 线性递推 的题且矩阵很难构造。

那么可以 暴力递推/打表 出超过两倍矩阵阶数的长度,然后 BM+线性递推 得到这个序列的任意项。

不知道矩阵阶数就 能找多长,找多长 了。

某些特殊情况下也可以代替 DFA的最小化

打表题也可以试着找一下规律,因为只能找线性递推的规律,所以大部分情况要灵活处理,比如说先差分再找规律之类的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Average

Average 题意&#xff1a; 矩阵W的值可以通过数组a和b得到&#xff0c;W[i][j]a[i]b[j],现在求W的一个子矩阵&#xff0c;平均值最大&#xff0c;且子矩阵必须满足宽度至少是x&#xff0c;高度至少是y&#xff0c;计算最大平均值 题解&#xff1a; 那答案就变成了分别对a和b…

开箱即用Bumblebee独立部署搭建webapi网关详解

在之前的章节里都是讲述如何在程序中使用Bumblebee来构建一个Webapi网关&#xff1b;但这样显然有些麻烦&#xff0c;毕竟很多时候可能只需要一个简单负载处理&#xff0c;还需要写个程序针对服务进行编写代码或配置的确是比较麻烦的事情&#xff1b;如果有负载方面的调整还需要…

LCS(2021牛客多校4)

LCS(2021牛客多校4) 题意&#xff1a; 让你构造三个字符串s1,s2,s3&#xff0c;长度均为n,要求LCS(s1,s2)a,LCS(s2,s3)b,LCS(s1,s3)c 题解&#xff1a; 先考虑三个串互相LCS为x,y,z,且x>y>z 显然如果xy-n>z则无解&#xff0c;反之xy-n<z有解 那么就先给三个串加…

CodeForces 1616H Keep XOR Low {a^b≤x} / CodeForces gym102331 Bitwise Xor {a^b≥x}(trie树 + 计数)

文章目录CodeForces 1616H Keep XOR LowproblemsolutioncodeCodeForces gym102331 Bitwise XorproblemsolutioncodeCodeForces 1616H Keep XOR Low problem 洛谷链接 solution 虽然选的是一个子集&#xff0c;但本质还是二元限制。 这非常类似以前做过的题目&#xff0c;已…

ASP.NET Core 文件系统

静态文件 目录浏览 默认页面 MIME类型配置 实战文件服务器 紧接上一讲 中间件 之后&#xff0c;今天来我们来讲一下关于 ASP.NET Core 中静态文件服务。什么是静态文件&#xff1f;先看一下下面例子&#xff08;在客户端浏览器中通过 url 路径访问了网站的一张图片&#xff09…

[C++] iota语句的语法

头文件为 numeric #include <numeric> using namespace std;语法和 sort / lower_bound / upper_bound 等差不多&#xff0c;都是前闭后开的原则。 iota(Ax,Ay,z) &#xff1a;表示将 AAA 数组的 [x,y)[x,y)[x,y) 区间进行填充&#xff0c;从 zzz 开始&#xff0c;每填…

如何使用vs将asp.net core项目添加容器支持并发布docker镜像到私有dockerhub和添加k8s/helm管理...

这篇文章介绍一下&#xff0c;如何使用VS2017给asp.net core添加容器支持&#xff0c;并发布镜像到私有docker hub&#xff0c;然后用chart管理容器镜像的操作流程。话不多说&#xff0c;just do it.新建项目首先新建一个asp.net core项目&#xff0c;这里我新建一个WebApi默认…

Inverse Pair

Inverse Pair 题意&#xff1a; 一个数组a&#xff0c;现在构造一个数组c&#xff0c;c[i]a[i]0/1&#xff08;0或1&#xff09;&#xff0c;使得c的逆序对最少 题解&#xff1a; 如果x在x1的后面&#xff0c;我们让x这个数1,x1不变&#xff0c;就可以让逆序对少1。如果x在…

CodeForces 1610H Squid Game(延迟贪心 + 构造 + 树状数组)

problem 洛谷链接 solution 考虑重新随便钦定一个点为“根”&#xff0c;并且强制根必须是关键点。 则所有 x−yx-yx−y 不是直系祖先-子代的要求&#xff08;要求Ⅰ&#xff09;&#xff0c;即 xxx 不是 yyy 祖先&#xff0c;yyy 也不是 xxx 祖先&#xff0c;一定都被满足…

P4551 最长异或路径

P4551 最长异或路径 题意&#xff1a; 给定一棵 n 个点的带权树&#xff0c;结点下标从 1 开始到 n。寻找树中找两个结点&#xff0c;求最长的异或路径。 异或路径指的是指两个结点之间唯一路径上的所有边权的异或。 题解&#xff1a; 我们指定1为根节点&#xff0c;T(u,v…

[小技巧]EF Core中如何获取上下文中操作过的实体

原文地址&#xff1a;https://www.cnblogs.com/lwqlun/p/10576443.html作者&#xff1a;Lamond Lu 源代码&#xff1a;https://github.com/lamondlu/EFCoreFindSample背景介绍当我们在工作单元(UnitOfWork)中使用EF/EF Core的时候&#xff0c;为了要保持事务&#xff0c;一个用…

CF1621G Weighted Increasing Subsequences(离散化+树状数组优化dp+栈维护后缀最大值+计数)

problem luogu-link solution 显然单独考虑每个 iii 的贡献&#xff0c;即被多少个合法上升子序列包含。 令 xmax⁡{j∣j>i∧aj>ai}x\max\{j\ |\ j>i\wedge a_j>a_i\}xmax{j ∣ j>i∧aj​>ai​}&#xff0c;则包含 iii 的合法子序列的结尾元素最远只能到…

Acwing 232. 守卫者的挑战

Acwing 232. 守卫者的挑战 题意&#xff1a; 有n个挑战&#xff0c;一开始背包容量为k&#xff0c;每次挑战有p[i]的概率成功&#xff0c;成功的话会得到一个大小为1的地图碎片或者是提升背包容量X&#xff0c;所有的地图碎片必须装在包里&#xff0c;问最后带地图离开的概率…

IdentityServer4-前后端分离之Vue

前言之前文章讲到如何使用Node.jsExpress构建JavaScript客户端&#xff0c;实现前后端分离。本节将介绍如何使用Vue实现前后端分离&#xff0c;文中介绍Vue的知识比较基础&#xff0c;适合新手学习。一、搭建Vue项目前提条件&#xff1a;安装nodejs、webpack和vue-cli。这个网上…

P1850 [NOIP2016 提高组] 换教室

P1850 [NOIP2016 提高组] 换教室 题意&#xff1a; 有2n个课安排在n个时间段上&#xff0c;每个时间段上都有两个一样的课同时在不同地方上&#xff0c;起初牛牛被所有课都被安排在Ci上课&#xff0c;另一节课在Di上课。牛牛现在想跟换到Di位置&#xff0c;它最多可以申请m节…

守列划分问题(圆排列+排列dp+结论)

problem 将正整数 1∼n1\sim n1∼n 任意划分成 mmm 个非空集合 A1,...,AmA_1,...,A_mA1​,...,Am​。 一个划分是守序的&#xff0c;当且仅当存在一个环排列 (p1,...,pm)(p_1,...,p_m)(p1​,...,pm​)&#xff0c;使得 max⁡Api>min⁡Api−1\max A_{p_i}>\min A_{p_{i-…

ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署(三

在上文ASP.NET Core应用程序容器化、持续集成与Kubernetes集群部署&#xff08;二&#xff09;中&#xff0c;我介绍了如何使用Azure DevOps为ASP.NET Core应用程序案例&#xff1a;tasklist搭建持续集成环境。在持续集成的过程中&#xff0c;Azure DevOps的Build Pipeline会下…

ASP.NET Core开源Web应用程序框架ABP

"作为面向服务架构(SOA)的一个变体,微服务是一种将应用程序分解成松散耦合服务的新型架构风格. 通过细粒度的服务和轻量级的协议,微服务提供了更多的模块化,使应用程序更容易理解,开发,测试,并且更容易抵抗架构侵蚀. 它使小型团队能够开发,部署和扩展各自的服务,实现开发的…

CodeForces 1517G Starry Night Camping(网络流最小割)

CodeForces 1517G Starry Night Camping problem 洛谷链接 solution 这个平行四边形的脑洞我™真的长见识了 本题最离谱的要求就是&#xff1a;平行四边形的一条边平行于 xxx 轴。 而往往这种离谱要求就是正解的途径。(((φ(◎ロ◎;)φ))) 首先不观察也能知道&#xff0c…

Acwing 307. 连通图

Acwing 307. 连通图 题意&#xff1a; 求 N 个节点的无向连通图有多少个&#xff0c;节点有标号&#xff0c;编号为 1∼N。 例如下列图示&#xff0c;三个节点的无向连通图共 4 个。 题解: 用py写 代码&#xff1a; def c(n, m):n int(n)m int(m)ret 1for i in range(…