请阅读本文的同学们注意:之前这篇博客和所附代码有点问题,求的不一定是最短递推式,非常抱歉

看毛爷爷的论文大概断断续续看了一个月了,看得不是很懂,google了一波好像很快就看懂了,就先口胡一下这个算法好了。这篇文章的介绍方式大概和毛爷爷的论文不大一致,当然算法的本质是一致的。

参考链接:https://grocid.net/2012/11/22/berlekamp-massey-algorithm-explained/

Berlekamp-Massey算法是用来求一个数列的递推式的。

我现在有一个序列$x_1,x_2...x_n$,首先我们先来定义递推式。序列x的递推式是个序列$p_1,p_2...p_m$。一个合法递推式满足对于$i\geq{m+1}$,$x_i=\sum_{j=1}^mp_jx_{i-j}$。一个递推式的次数定义为m,注意这里的每个p都可以为0。

我们定义一个递推式带入一个序列的第i项所得的结果为$\sum_{j=1}^mx_{i-j}p_j-x_i$,如果$i\leq{m}$定义为0。那么合法递推式就是带进去每一项都得0的递推式对吧。

好,现在我们想要求递推式。怎么求呢,我们开始随便口胡一个递推式,就{}好了。

我们考虑第一个数,这样一个一个往下考虑。我们看看现在这个多项式满不满足x[i],满足就留着。

如果不满足,我们就要想办法修复这个递推多项式对吧。

一种naive的想法就是说我开始有个递推多项式为g,它对于前i-1项全成立,到了第i项挂了。我们来算算这个递推式带进第i项,假设是s,那么我们要想办法把带进去得到的值减去s。

如果我们凭空变出一个递推式f,它满足这个递推式带进前i-1项全为0,带进第i项是1,那么我们只要把g减去sf不就行了吗。

如果我们不是第一次遇到这种情况,那么我们之前也曾经有一个递推式,它满足前j-1项,带进去恰好在第j项不为0,不妨假设在第j项为1,如果不为1除掉即可。那么我们只要在这个递推式稍微移一移项,前面补若干个0就可以得到f了。

如果有多个满足条件的递推式?那么我们选择最近的一个肯定最优。

我们可以维护当前最优的一个递推式,使得它补完0之后的长度最少,取这个就行了。

我们来举个例子,我有一个数列1,2,4,10,24,50,116。

我们一个一个数考虑,首先数列里啥都没有,递推式是{}。

然后看到一个1,一脸懵逼,那么递推式随便写一个{0}好了。

接下来我们发现到了2这里挂了。之前1挂掉的经历告诉我们x[1]=1,那么我们令f={1},我们把递推式改成{2}好了。

接下来到了4,我们发现一切良好。

到了10,我们发现又挂了,带进去这项得到了-2。之前2挂的经历告诉我们x[2]=2,那么我们令f={0,0.5,0},把递推式加上2f={0,1,0},那么递推式变成了{2,1,0}。(注意这里结尾有一个0,因为之前递推式里面是{0})

到了24,一切良好。

到了50,我们发现又挂了,带进去得到了8。之前10挂的经历告诉我们-x[4]+2x[3]=-2,那么两边除以-2,0.5x[4]-x[3]=1,所以可以令f={0,0.5,-1},那么8f={0,4,-8},所以递推式要减去8f,变成了{2,-3,8}。

到了116,又挂掉了,带进去得到了-8。之前50的狗带经历告诉我们-x[6]+2x[5]+x[4]=8,那么两边除以8得到-0.125x[6]+0.25x[5]+0.125x[4]=1,那么令f={-0.125,0.25,0.125,0},8f={-1,2,1,0},那么递推式要加上8f,变成{1,-1,9,0}(这里结尾的0是因为原来带了一个0)。

实际程序写起来还是挺简单的。

int n,pn=,fail[];
typedef vector<ld> vld;
vld ps[]; ld x[],delta[];
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%lf",x+i);
int best=;
for(int i=;i<=n;i++)
{
ld dt=-x[i];
for(int j=;j<ps[pn].size();j++)
dt+=x[i-j-]*ps[pn][j];
delta[i]=dt;
if(fabs(dt)<=1e-) continue;
fail[pn]=i; if(!pn) {ps[++pn].resize(i); continue;}
vld&ls=ps[best]; ld k=-dt/delta[fail[best]];
vld cur; cur.resize(i-fail[best]-); //trailing 0
cur.pb(-k); for(int j=;j<ls.size();j++) cur.pb(ls[j]*k);
if(cur.size()<ps[pn].size()) cur.resize(ps[pn].size());
for(int j=;j<ps[pn].size();j++) cur[j]+=ps[pn][j];
if(i-fail[best]+(int)ps[best].size()>=ps[pn].size()) best=pn;
ps[++pn]=cur;
}
for(unsigned g=;g<ps[pn].size();g++)
cout<<ps[pn][g]<<" "; puts("");
}

什么,卡空间?只有两项是有用的,可以滚动数组。

由于某种原因,具体应用下一篇再说好了。下一篇鸽了

那么Berlekamp-Massey算法有啥用呢?比如我有一个优秀的dp,f[i][j]表示某种神奇的量,然后对1<=i<=n,j<=m,$f[i][j]=\sum_s f[i-1][s]*val[j][s]$,val是与i无关的量,然后要求f[n][1]之类的。以前我们用矩阵快速幂,现在我们就可以用BM算出f[n][1]的递推式,然后闷声m^2logn。

以下附赠一个素质二连板子:

const int MOD=1e9+;
ll qp(ll a,ll b)
{
ll x=; a%=MOD;
while(b)
{
if(b&) x=x*a%MOD;
a=a*a%MOD; b>>=;
}
return x;
}
namespace linear_seq {
inline vector<int> BM(vector<int> x)
{
vector<int> ls,cur;
int pn=,lf,ld;
for(int i=;i<int(x.size());++i)
{
ll t=-x[i]%MOD;
for(int j=;j<int(cur.size());++j)
t=(t+x[i-j-]*(ll)cur[j])%MOD;
if(!t) continue;
if(!cur.size())
{cur.resize(i+); lf=i; ld=t; continue;}
ll k=-t*qp(ld,MOD-)%MOD;
vector<int> c(i-lf-); c.pb(-k);
for(int j=;j<int(ls.size());++j) c.pb(ls[j]*k%MOD);
if(c.size()<cur.size()) c.resize(cur.size());
for(int j=;j<int(cur.size());++j)
c[j]=(c[j]+cur[j])%MOD;
if(i-lf+(int)ls.size()>=(int)cur.size())
ls=cur,lf=i,ld=t;
cur=c;
}
vector<int>&o=cur;
for(int i=;i<int(o.size());++i)
o[i]=(o[i]%MOD+MOD)%MOD;
return o;
}
int N; ll a[SZ],h[SZ],t_[SZ],s[SZ],t[SZ];
inline void mull(ll*p,ll*q)
{
for(int i=;i<N+N;++i) t_[i]=;
for(int i=;i<N;++i) if(p[i])
for(int j=;j<N;++j)
t_[i+j]=(t_[i+j]+p[i]*q[j])%MOD;
for(int i=N+N-;i>=N;--i) if(t_[i])
for(int j=N-;~j;--j)
t_[i-j-]=(t_[i-j-]+t_[i]*h[j])%MOD;
for(int i=;i<N;++i) p[i]=t_[i];
}
inline ll calc(ll K)
{
for(int i=N;~i;--i) s[i]=t[i]=;
s[]=; if(N!=) t[]=; else t[]=h[];
for(;K;mull(t,t),K>>=) if(K&) mull(s,t); ll su=;
for(int i=;i<N;++i) su=(su+s[i]*a[i])%MOD;
return (su%MOD+MOD)%MOD;
}
inline int gao(vector<int> x,ll n)
{
if(n<int(x.size())) return x[n];
vector<int> v=BM(x); N=v.size(); if(!N) return ;
for(int i=;i<N;++i) h[i]=v[i],a[i]=x[i];
return calc(n);
}
}

你可以用这个数据来测试你的BM板子:https://files.cnblogs.com/files/zzqsblog/BM-data.zip (mod 1e9+7,最短长度为712或713)

就先更到这里吧。

Berlekamp-Massey算法简单介绍的更多相关文章

  1. 算法笔记_071:SPFA算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个 ...

  2. 垃圾回收算法简单介绍——JVM读书笔记&lt;二&gt;

    垃圾回收的过程主要包含两部分:找出已死去的对象.移除已死去的对象. 确定哪些对象存活有两种方式:引用计数算法.可达性分析算法. 方案一:引用计数算法 给对象中加入一个引用计数器.每当有一个地方引用它时 ...

  3. 算法笔记_068:Dijkstra算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 使用Dijkstra算法得到最短距离示例 2.2 具体编码   1 问题描述 何为Dijkstra算法? Dijkstra算法功能:给出加权连通图中一个顶点, ...

  4. Paxos算法简单介绍

    一种基于消息传递且具有高度容错特性的一致性算法.解决在存在宕机或者网络异常的集群中对某个数据的值达成一致性,并且保证无论在发生以上任何异常都不会破坏整个系统的一致性,具有容错性. Paxos算法实现的 ...

  5. 算法笔记_070:BellmanFord算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为BellmanFord算法? BellmanFord算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶 ...

  6. 算法笔记_069:Floyd算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 使用Floyd算法得到最短距离示例 2.2 具体编码   1 问题描述 何为Floyd算法? Floyd算法功能:给定一个加权连通图,求取从每一个顶点到其它所 ...

  7. PrincetonUniversity-Coursera 算法:算法简单介绍

    Course Overview What is this course? Intermediate-level survey course. Programming and proble solvin ...

  8. Berlekamp Massey算法求线性递推式

    BM算法求求线性递推式   P5487 线性递推+BM算法   待AC.   Poor God Water   // 题目来源:ACM-ICPC 2018 焦作赛区网络预赛 题意   God Wate ...

  9. 简单介绍一下R中的几种统计分布及常用模型

    统计学上分布有很多,在R中基本都有描述.因能力有限,我们就挑选几个常用的.比较重要的简单介绍一下每种分布的定义,公式,以及在R中的展示. 统计分布每一种分布有四个函数:d――density(密度函数) ...

随机推荐

  1. ZOJ 2110 DFS

    狗要出门,且正好在T秒 就是DFS + 剪枝, 联系一下剪枝技巧 #include<iostream> #include<cstdio> #include<cstring ...

  2. pip的常用命令

    前言 pip作为Python的御用包管理工具有着强大的功能,但是许多命令需要我们使用的时候借助搜索引擎查找(尤其是我), 于是我想将我使用到的命令整合下来,以后不用麻烦去找了,也希望能给你带来帮助.文 ...

  3. 并发性能的隐形杀手之伪共享(false sharing)

    在并发编程过程中,我们大部分的焦点都放在如何控制共享变量的访问控制上(代码层面),但是很少人会关注系统硬件及 JVM 底层相关的影响因素.前段时间学习了一个牛X的高性能异步处理框架 Disruptor ...

  4. 洛谷P5072 [Ynoi2015]盼君勿忘 [莫队]

    传送门 辣鸡卡常题目浪费我一下午-- 思路 显然是一道莫队. 假设区间长度为\(len\),\(x\)的出现次数为\(k\),那么\(x\)的贡献就是\(x(2^{len-k}(2^k-1))\),即 ...

  5. RedHat Linux关闭seLinux命令

    Redhat使用了SELinux来增强安全,关闭的办法为: 1. 永久有效 修改 /etc/selinux/config 文件中的 SELINUX="" 为 disabled ,然 ...

  6. swift 学习- 20 -- 错误处理

    // 错误处理 是响应错误以及 从错误中恢复的过程, Swift 提供了在运行时对 可恢复错误的 抛出, 捕获, 传递 和 操作的支持 // 某些操作无法保证总是执行完所有代码 或总是生层有用结果, ...

  7. 解决 安装或卸载软件时报错Error 1001 的问题

    卸载或安装程序时出错1001:错误1001可能发生在试图更新.修复或卸载windows os中的特定程序时.此问题通常是由于程序的先前安装损坏而引起的. 错误“1001”通常会遇到,因为程序的先前安装 ...

  8. SQLServer 2014 本地机房HA+灾备机房DR解决方案

    SQLServer 2014 主数据中心HA+灾备机房DR解决方案 SQLServer 2008 的时候使用 local WSFC+DR Mirror方式,对象是单数据库 两个单独的 WSFC 上使用 ...

  9. 开源框架 ImageLoader +ListView+GridView+RecyclerView 浅解

    下载地址 链接:https://pan.baidu.com/s/1ebz99pcuvHg2bODgeOtSbg 提取码:ia39 一.导入jar包或者添加依赖 jar包地址 导入jar包:将下载的ja ...

  10. python函数之各种器

    一: 装饰器 1:装饰器模板 def wrapper(func): def inner(*args,**kwargs): ret =func(*args,**kwargs) return ret re ...