BM(Berlekamp-Massey)算法
线性递推的题目区域赛里还是挺多的,还是有必要学一下
~ 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)算法的更多相关文章
- Berlekamp Massey算法求线性递推式
BM算法求求线性递推式 P5487 线性递推+BM算法 待AC. Poor God Water // 题目来源:ACM-ICPC 2018 焦作赛区网络预赛 题意 God Wate ...
- BF、KMP、BM、Sunday算法讲解
BF.KMP.BM.Sunday算法讲解 字串的定位操作通常称作串的模式匹配,是各种串处理系统中最重要的操作之一. 事实上也就是从一个母串中查找一模板串,判定是否存在. 现给出四种匹配算法包括BF(即 ...
- Horspool和BM算法解析
最近算法中学到了Horspool,KMP,BM三种算法.接下来给大家做个分享. Horspool算法: 算法思路: 1.分为匹配串,原串 2.从右往左依次匹配: 一旦遇到不匹配的,原串相对于匹配串 移 ...
- BM算法和Sunday快速字符串匹配算法
BM算法研究了很久了,说实话BM算法的资料还是比较少的,之前找了个资料看了,还是觉得有点生涩难懂,找了篇更好的和算法更好的,总算是把BM算法搞懂了. 1977年,Robert S.Boyer和J St ...
- 双目深度估计传统算法流程及OpenCV的编译注意事项
起因: 1. 双目立体视觉中双目深度估计是非常重要且基础的部分,而传统的立体视觉的算法基本上都在opencv中有相对优秀的实现.同时考虑了性能和效率.因此,学习使用opencv接口是非常重要的. 2. ...
- 数据结构 Sunday算法
Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配算法.相对比较KMP和BM算法而言,简单了许多. Sunday算法的思想类似于BM算法中的坏字符思想,有点像其删减版.差 ...
- 字符串匹配 - sunday算法
常见的字符串匹配算法有BF.KMP(教科书中非常经典的).BM.Sunday算法 这里主要想介绍下性能比较好并且实现比较简单的Sunday算法 . 基本原理: 从前往后匹配,如果遇到不匹配情况判断母串 ...
- 前端与算法 leetcode 28.实现 strStr()
# 前端与算法 leetcode 28.实现 strStr() 题目描述 28.移除元素 概要 这道题的意义是实现一个api,不是调api,尽管很多时候api的速度比我们写的快(今天这个我们可以做到和 ...
- BF,BM,KMP,就这?
为保证代码严谨性,文中所有代码均在 leetcode 刷题网站 AC ,大家可以放心食用. 皇上生辰之际,举国同庆,袁记菜馆作为天下第一饭店,所以被选为这次庆典的菜品供应方,这次庆典对于袁记菜馆是一项 ...
- [算法2-数组与字符串的查找与匹配] (.NET源码学习)
[算法2-数组与字符串的查找与匹配] (.NET源码学习) 关键词:1. 数组查找(算法) 2. 字符串查找(算法) 3. C#中的String(源码) 4. 特性Attribute 与内 ...
随机推荐
- 解决Windows7下virtualbox安装ubuntu出现的0x00000000指令引用0x00000000内存,该内存不能为written问题
公司电脑只能用Windows7,不能用10,也没WSL用,最近想跑个Linux环境,因为之前装docker toolbox装了virtualbox,没道理再装vmware,遂用vbox开始折腾,没想到 ...
- 20175316盛茂淞 2018-2019-2 《Java程序设计》第11周学习总结
20175316 <Java程序设计> 第11周学习总结 教材内容学习总结 第十三章 URL类 URL类是java.net包中的一个重要的类,URL的实例封装着一个统一资源定位符,使用UR ...
- (JavaScript) 百度地图与腾讯地图坐标转换
/** * 坐标转换,百度地图坐标转换成腾讯地图坐标 * lng 腾讯经度(pointy) * lat 腾讯纬度(pointx) * 经度>纬度 */ function bMapToQQMap( ...
- WCF-初识DEMO
类库 System.ServiceModle WCF类库 契约IUser1,实现User1 [ServiceContract] public interface IUser1 { [Operation ...
- js实现放烟花效果——点击处会从下向上升起烟花
一个box中,点击其中的任意位置,会有烟花从正下方升起到点击处,并燃放出一圈圆形的烟花.代码如下: 首先是布局以及样式: <style> .box{ width: 1100px; heig ...
- js时间戳与日期格式之间相互转换
###js时间戳与日期格式之间相互转换 将时间戳转换成日期格式 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法, ...
- VMware安装windows2003
一.安装vm 这一项大家应该都会,网上也有很多教程. 二.搭建Windows server 2003 1.镜像下载- 2.虚拟机安装 首先是新建虚拟机,我选的是自定义,也可以选典型 第一步默认下一步, ...
- 笔记-5:mysql数据更新
1.插入数据 1.1 插入完整的数据 # 语法格式: INSERT INTO tb_name(column_list) VALUES(value_list); tb_name:指定要插入数据的表名. ...
- Layui连接mysql操作CRUD案例
今天分享的是一个新前端框架Layui,用它来链接数据库实现一下crud的操作. 一:layui简历 layui,是一款采用自身模块规范编写的前端 UI 框架,遵循原生 HTML/CSS/JS 的书写与 ...
- Luogu5363 SDOI2019移动金币(博弈+动态规划)
容易想到可以转化为一个有m堆石子,石子总数不超过n-m的阶梯博弈.阶梯博弈的结论是相当于只考虑奇数层石子的nim游戏. nim和不为0不好算,于是用总方案数减掉nim和为0的方案数.然后考虑dp,按位 ...