线性递推的题目区域赛里还是挺多的,还是有必要学一下


~ BM(Berlekamp-Massey)算法 ~

有一个$n$阶线性递推$f$,想要计算$f(m)$,有一种常用的办法是矩阵快速幂,复杂度是$O(n^3logm)$

在不少情况下这已经够用了,但是如果$n$比较大、到了$10^3$级别,这就不太适用了

而BM算法能将这个复杂度压低到$O(n^2logm)$,若加上NTT优化的话能做到$O(n^2+nlognlogm)$,十分厉害

这个算法的核心是将$f(m)$用递推的前$n$项表示

即,已知$f(0),...,f(n-1)$和递推式$f(m)=a_0f(m-1)+...+a_{n-1}f(m-n)$,该算法是求出系数$W_0,...,W_{n-1}$,使得$f(m)=W_0f(n-1)+...+W_{n-1}f(0)$

看似无从下手?实际上只要大力展开就行了

根据定义,有(只是写成$\sum$的形式而已)

\[f(m)=\sum_{i=0}^{n-1}a_i f(m-1-i)\]

而对于每一项再次展开,即

\[f(m-1-i)=\sum_{j=0}^{n-1}a_j f(m-1-i-1-j)\]

全部代入,能得到

\[f(m)=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_ia_j f(m-2-i-j)\]

把式子写的更好看一点,就是

\[f(m)=\sum_{k=0}^{2n-2}\sum_{i+j=k}a_ia_j f(m-2-k)\]

这样做之后有什么用呢?

在原本的递推式中,$f(m)$可以通过$f(m-1),...,f(m-n)$这$n$个项表示

各项展开后,就可以通过$f(m-2),...,f(m-2n)$表示

事实上,我们可以再依次对$f(m-i),2\leq i\leq n$展开,并将系数向$f(m-i-1),...,f(m-i-n)$并入,最终就能把原递推式通过$f(m-n-1),...,f(m-2n)$这$n$项表示

于是可以得到一个新的$n$阶递推式,记为$f(m)=b_0f(m-n+1),...,b_{n-1}f(m-2n)$

再用新递推式将各项展开,就可以通过$f(m-2n-2),...,f(m-4n)$表示

再用原递推式展开$f(m-2n-i),2\leq i\leq n$并向前合并系数,最终就能把原递推式通过$f(m-3n+1),...,f(m-4n)$这$n$项表示

之后都是类似的了,不再赘述

有了上面的思路,就可以用类似快速幂的方法,得到$f(m)=W_0f(m-(k-1)n+1),...,W_{n-1}f(m-kn)$这样的展开式,其中$m-kn<n$

余数$m-kn$是我们不喜欢的,但也没有必要整体再向前推,一开始计算时算出$f(0),...,f(2n-1)$就够了

按照上述思路能这样实现:

#include <cstdio>
#include <cstring>
using namespace std; typedef long long ll;
const int MOD=;
const int N=; int n,m;
int a[N];
int f[N<<]; int tmp[N<<]; void mul(int *y,int *x)
{
memset(tmp,,sizeof(tmp)); for(int i=;i<n;i++)
for(int j=;j<n;j++)
tmp[i+j]=(tmp[i+j]+ll(y[i])*x[j])%MOD; for(int i=;i<n-;i++)
for(int j=;j<n;j++)
tmp[i+j+]=(tmp[i+j+]+ll(tmp[i])*a[j])%MOD; for(int i=;i<n;i++)
y[i]=tmp[i+n-];
} int w[N<<],x[N<<]; int BM()
{
if(m<(n<<))
return f[m]; for(int i=;i<n;i++)
x[i]=a[i],w[i]=a[i]; int t=(m-n)/n;
int rem=m-n-t*n; while(t)
{
if(t&)
mul(w,x);
mul(x,x);
t>>=;
} int res=;
for(int i=;i<n;i++)
res=(res+ll(w[i])*f[rem+n-i-])%MOD;
return res;
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
scanf("%d",&a[i]);
for(int i=;i<n;i++)
scanf("%d",&f[i]);
for(int i=n;i<(n<<);i++)
for(int j=;j<=n;j++)
f[i]=(f[i]+ll(a[j-])*f[n-j])%MOD; printf("%d\n",BM());
return ;
}

想做的更快的话,一个是要写NTT,另一个是合并系数会比较困难,待补


因为这题学的BM:牛客ACM 882B ($Eddy$ $Walker$ $2$)

$m\rightarrow \infty$时,$f(m)\rightarrow \frac{2}{k+1}$ (并不会证...)

从rls那里学了一个证明:

走$k$步,期望能走的长度是$1+2+...+k=\frac{k(k+1)}{2}$

那么在这段距离中,每个位置被走过的概率就是$\frac{k}{\frac{k(k+1)}{2}}=\frac{2}{k+1}$

在其他时候,直接套上面的板子即可

牛客的玄学评测机,同一份代码能差出500ms = =

#include <cstdio>
#include <cstring>
using namespace std; typedef long long ll;
const int MOD=;
const int N=; inline int quickpow(int x,int t)
{
int res=;
while(t)
{
if(t&)
res=ll(res)*x%MOD;
x=ll(x)*x%MOD;
t>>=;
}
return res;
} inline int rev(int x)
{
return quickpow(x,MOD-);
} int n,rn;
ll m;
int a[N];
int f[N<<]; int tmp[N<<]; void mul(int *y,int *x)
{
memset(tmp,,sizeof(tmp)); for(int i=;i<n;i++)
for(int j=;j<n;j++)
tmp[i+j]=(tmp[i+j]+ll(y[i])*x[j])%MOD; for(int i=;i<n-;i++)
for(int j=;j<n;j++)
tmp[i+j+]=(tmp[i+j+]+ll(tmp[i])*a[j])%MOD; for(int i=;i<n;i++)
y[i]=tmp[i+n-];
} int w[N<<],x[N<<]; int BM()
{
if(m<(n<<))
return f[m]; for(int i=;i<n;i++)
x[i]=a[i],w[i]=a[i]; ll t=(m-n)/n;
int rem=m-n-t*n; while(t)
{
if(t&)
mul(w,x);
mul(x,x);
t>>=;
} int res=;
for(int i=;i<n;i++)
res=(res+ll(w[i])*f[rem+n-i-])%MOD;
return res;
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&m); if(m==-)
{
printf("%d\n",2LL*rev(n+)%MOD);
continue;
} rn=rev(n);
for(int i=;i<n;i++)
a[i]=rn; memset(f,,sizeof(f));
f[]=;
for(int i=;i<(n<<);i++)
for(int j=;j<=n && j<=i;j++)
f[i]=(f[i]+ll(rn)*f[i-j])%MOD; printf("%d\n",BM());
} return ;
}

比较特定的知识点吧,以后遇到就是赚到(然后发现强制NTT,直接白给= =)

(完)

BM(Berlekamp-Massey)算法的更多相关文章

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

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

  2. BF、KMP、BM、Sunday算法讲解

    BF.KMP.BM.Sunday算法讲解 字串的定位操作通常称作串的模式匹配,是各种串处理系统中最重要的操作之一. 事实上也就是从一个母串中查找一模板串,判定是否存在. 现给出四种匹配算法包括BF(即 ...

  3. Horspool和BM算法解析

    最近算法中学到了Horspool,KMP,BM三种算法.接下来给大家做个分享. Horspool算法: 算法思路: 1.分为匹配串,原串 2.从右往左依次匹配: 一旦遇到不匹配的,原串相对于匹配串 移 ...

  4. BM算法和Sunday快速字符串匹配算法

    BM算法研究了很久了,说实话BM算法的资料还是比较少的,之前找了个资料看了,还是觉得有点生涩难懂,找了篇更好的和算法更好的,总算是把BM算法搞懂了. 1977年,Robert S.Boyer和J St ...

  5. 双目深度估计传统算法流程及OpenCV的编译注意事项

    起因: 1. 双目立体视觉中双目深度估计是非常重要且基础的部分,而传统的立体视觉的算法基本上都在opencv中有相对优秀的实现.同时考虑了性能和效率.因此,学习使用opencv接口是非常重要的. 2. ...

  6. 数据结构 Sunday算法

    Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配算法.相对比较KMP和BM算法而言,简单了许多. Sunday算法的思想类似于BM算法中的坏字符思想,有点像其删减版.差 ...

  7. 字符串匹配 - sunday算法

    常见的字符串匹配算法有BF.KMP(教科书中非常经典的).BM.Sunday算法 这里主要想介绍下性能比较好并且实现比较简单的Sunday算法 . 基本原理: 从前往后匹配,如果遇到不匹配情况判断母串 ...

  8. 前端与算法 leetcode 28.实现 strStr()

    # 前端与算法 leetcode 28.实现 strStr() 题目描述 28.移除元素 概要 这道题的意义是实现一个api,不是调api,尽管很多时候api的速度比我们写的快(今天这个我们可以做到和 ...

  9. BF,BM,KMP,就这?

    为保证代码严谨性,文中所有代码均在 leetcode 刷题网站 AC ,大家可以放心食用. 皇上生辰之际,举国同庆,袁记菜馆作为天下第一饭店,所以被选为这次庆典的菜品供应方,这次庆典对于袁记菜馆是一项 ...

  10. [算法2-数组与字符串的查找与匹配] (.NET源码学习)

    [算法2-数组与字符串的查找与匹配] (.NET源码学习) 关键词:1. 数组查找(算法)   2. 字符串查找(算法)   3. C#中的String(源码)   4. 特性Attribute 与内 ...

随机推荐

  1. 【数据库开发】MySQL命令大全

    1.连接Mysql 格式: mysql -h主机地址 -u用户名 -p用户密码1.连接到本机上的MYSQL. 首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root ...

  2. python argparse库

    argparse用法总结 https://blog.csdn.net/qq_24551305/article/details/90155858 args = parse.parse_args()par ...

  3. mac清除launchpad 应用程序和图标

    打开launchpad显示所有的程序,有时候却无法删除一些应用图标和程序 用Spotlight(command+空格键),我们输入要删除的应用名称 我们按住Command再点回车, 搜索的结果就会在f ...

  4. [学习笔记] Blender 常用工具 移动与旋转,缩放, 变换

    点击上面的移动图标之后,可在X,Y,Z轴移动物体. shift+S 之后,可有更多的移动选项. 旋转:可沿X,Y, Z 进行旋转 缩放 还可输入缩放的具体数值,更精确. 变换 可同时做移动.旋转.缩放 ...

  5. Python爬虫入门教程之BeautifulSoup

    模块安装 pip3 install beautifulsoup4 模块导入 from bs4 import BeautifulSoup 示例html内容 RPC是一种比较流行的RPC通信框架,由谷歌公 ...

  6. 【转帖】循序渐进Oracle:数据库的字符集和字符集文件

    循序渐进Oracle:数据库的字符集和字符集文件 https://blog.csdn.net/Enmotech/article/details/100869162 2019年09月15日 18:23: ...

  7. 版本管理——Git和SVN的介绍及其优缺点

    版本管理 概念:版本管理是软件配置管理的基础,它管理并保护开发者的软件资源.   好处:可以保留我们的历史版本,在代码开发到一半的时候,不至于无故丢失,还可以查看BUG的来龙去脉.   版本管理种类: ...

  8. git使用中的一些命令及心得

    Git 与 SVN 区别点: 1.Git 是分布式的,SVN 不是:这是 Git 和其它非分布式的版本控制系统,例如 SVN,CVS 等,最核心 的区别. 2.Git 把内容按元数据方式存储,而 SV ...

  9. Django基础cookie和session

    Django基础cookie和session 1.会话跟踪 ​ 什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如给10086打个电话,你就是客户端, ...

  10. 如何在 arm 官网上找到合适的手册

    http://infocenter.arm.com/help/advanced/help.jsp 在这里输入合适的版号即可 这样就可以不用去 CSDN 了 100000_0000_00_EN - AR ...