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


~ 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=1000000007;
const int N=1005;int n,m;
int a[N];
int f[N<<1];int tmp[N<<1];void mul(int *y,int *x)
{memset(tmp,0,sizeof(tmp));for(int i=0;i<n;i++)for(int j=0;j<n;j++)tmp[i+j]=(tmp[i+j]+ll(y[i])*x[j])%MOD;for(int i=0;i<n-1;i++)for(int j=0;j<n;j++)tmp[i+j+1]=(tmp[i+j+1]+ll(tmp[i])*a[j])%MOD;for(int i=0;i<n;i++)y[i]=tmp[i+n-1];
}int w[N<<1],x[N<<1];int BM()
{if(m<(n<<1))return f[m];for(int i=0;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&1)mul(w,x);mul(x,x);t>>=1;}int res=0;for(int i=0;i<n;i++)res=(res+ll(w[i])*f[rem+n-i-1])%MOD;return res;
}int main()
{scanf("%d%d",&n,&m);for(int i=0;i<n;i++)scanf("%d",&a[i]);for(int i=0;i<n;i++)scanf("%d",&f[i]);for(int i=n;i<(n<<1);i++)for(int j=1;j<=n;j++)f[i]=(f[i]+ll(a[j-1])*f[n-j])%MOD;printf("%d\n",BM());return 0;
}

View Code

想做的更快的话,一个是要写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=1000000007;
const int N=1100;inline int quickpow(int x,int t)
{int res=1;while(t){if(t&1)res=ll(res)*x%MOD;x=ll(x)*x%MOD;t>>=1;}return res;
}inline int rev(int x)
{return quickpow(x,MOD-2);
}int n,rn;
ll m;
int a[N];
int f[N<<1];int tmp[N<<1];void mul(int *y,int *x)
{memset(tmp,0,sizeof(tmp));for(int i=0;i<n;i++)for(int j=0;j<n;j++)tmp[i+j]=(tmp[i+j]+ll(y[i])*x[j])%MOD;for(int i=0;i<n-1;i++)for(int j=0;j<n;j++)tmp[i+j+1]=(tmp[i+j+1]+ll(tmp[i])*a[j])%MOD;for(int i=0;i<n;i++)y[i]=tmp[i+n-1];
}int w[N<<1],x[N<<1];int BM()
{if(m<(n<<1))return f[m];for(int i=0;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&1)mul(w,x);mul(x,x);t>>=1;}int res=0;for(int i=0;i<n;i++)res=(res+ll(w[i])*f[rem+n-i-1])%MOD;return res;
}int main()
{int T;scanf("%d",&T);while(T--){scanf("%d%lld",&n,&m);if(m==-1){printf("%d\n",2LL*rev(n+1)%MOD);continue;}rn=rev(n);for(int i=0;i<n;i++)a[i]=rn;memset(f,0,sizeof(f));f[0]=1;for(int i=1;i<(n<<1);i++)for(int j=1;j<=n && j<=i;j++)f[i]=(f[i]+ll(rn)*f[i-j])%MOD;printf("%d\n",BM());}return 0;
}

View Code


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

(完)

转载于:https://www.cnblogs.com/LiuRunky/p/Berlekamp_Massey.html

BM(Berlekamp-Massey)算法学习笔记相关推荐

  1. Berlekamp–Massey算法简要介绍

    这是一篇翻译向的文章,笔者整理了一些有关Berlekamp–Massey算法的笔记,还增加了一些自己的理解. 下面列出了笔者写此文时所参考的一些资料: wikipedia fjzzq2002 别人的博 ...

  2. 基于MVS的三维重建算法学习笔记(四)— 立体匹配经典算法Semi-Global Matching(SGM)论文翻译及要点解读

    基于MVS的三维重建算法学习笔记(四)- 立体匹配经典算法Semi-Global Matching(SGM)论文翻译及要点解读 声明 SGM概述 Cost Calculation(像素代价计算)--M ...

  3. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

  4. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  5. 数据结构与算法学习笔记之 从0编号的数组

    数据结构与算法学习笔记之 从0编号的数组 前言 数组看似简单,但掌握精髓的却没有多少:他既是编程语言中的数据类型,又是最基础的数据结构: 一个小问题: 为什么数据要从0开始编号,而不是 从1开始呢? ...

  6. 输出dag的所有拓扑排序序列_算法学习笔记(53): 拓扑排序

    拓扑排序是对DAG(有向无环图)上的节点进行排序,使得对于每一条有向边 , 都在 之前出现.简单地说,是在不破坏节点 先后顺序的前提下,把DAG拉成一条链.如果以游戏中的科技树(虽然名字带树,其实常常 ...

  7. 算法学习笔记:对指定金额计算最少钞票数

    算法学习笔记:对指定金额计算最少钞票数 一.引出问题 财务人员给员工发工资时经常遇到这样一个问题,即根据每个人的工资额(以元作为单位)计算出各种面值的钞票的张数,且要求总张数最少.例如,某职工工资为3 ...

  8. matlab中x从0到5不含0,关于MATLAB的数学建模算法学习笔记

    关于MATLAB的数学建模算法学习笔记 目录 线性规划中应用: (3) 非线性规划: (3) 指派问题;投资问题:(0-1问题) (3) 1)应用fmincon命令语句 (3) 2)应用指令函数:bi ...

  9. 机器学习篇01:在线学习的支持向量机算法学习笔记

    在线学习的支持向量机算法学习笔记 oisvm算法实现说明 oisvm算法实现说明 % 本程序是用于实现基于在线学习的调制信号识别的程序 % % % 第一步:调制信号的生成 % 首先是7个信号:2ASK ...

  10. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

最新文章

  1. 可持久化线段树(主席树)【舰娘系列】【自编题】
  2. 霸榜多个CV任务,开源仅两天,微软分层ViT模型收获近2k star
  3. 假设训练数据集中有10万个词,四元语法需要存储多少词频和多词相邻频率?《动手学深度学习 李沐》 转
  4. NPTL简介 (NATIVE POSIX Thread Library)
  5. 计算机网络:socket-udp
  6. (chap1 网络基础知识)网络的构成要素:(7)网关
  7. Ubuntu 16.04 下部署Node.js+MySQL微信小程序商城
  8. Gem5全系统FS(full system)测试
  9. php 框架测试,PHP测试框架PHPUnit组织测试操作示例
  10. 搜索引擎字符串(亲测)
  11. 华为防火墙默认密码是什么?
  12. Apache Shiro 集成-Cas
  13. 优惠券使用/凑满减优惠/硬币组合问题(结果包括最优组合和最优值)
  14. Linux 2.6内核的设备模型
  15. [例说NLP]使用gensim处理wiki百科中文数据
  16. BugKu CTF(杂项篇MISC)---细心的大象
  17. xmd:AP transaction timeout: ACK = 0x01, expected=0x02)
  18. 合泰杯比赛总结(一)
  19. HDU2147 巴什博弈
  20. java中奖率算法_JS简单实现:根据奖品权重计算中奖概率实现抽奖的方法

热门文章

  1. PDFBox 字体缓存笔记
  2. 我们连站都站不好--从Taylor Swift的脖子说起
  3. delphi xe5 安装 fastreport5
  4. 【数据结构】栈与队列区分push pop offer poll containsKey put等
  5. 分享3款ipad笔记工具,你们快来
  6. 坚定的信念就是成功的一大半
  7. 旧主板怎么样用pcie扩展卡M.2 NVME协议固态硬盘装系统以及升级WIN11系统教程
  8. 【Vue】MyClassroom.vue 使用组件方法实现增删改查-20221226
  9. VIVADO-SDK开发SD卡读写时打不开FATFS函数的问题
  10. R语言使用table1包绘制(生成)三线表、使用双变量分列构建三线表、双变量分列三线表