两个 BM 哟

1.Bostan-Mori

常系数其次线性递推。

实际上这个算法是用来计算 \([x^n]\frac {F(x)}{G(x)}\) 的。。。

我们考虑一个神奇的多项式:\(F(x)F(-x)\)。容易发现存在一个多项式 \(H(x)\) 满足 \(H(x^2)=F(x)F(-x)\)。

于是我们对这个分式的分子和分母同时乘上 \(G(-x)\),能够得到有 \([x^n]\frac {F(x)G(-x)}{G(x)G(-x)}\)。

按照奇偶拆开,假设这玩意儿是 \([x^n]\frac {Q(x^2)+xP(x^2)}{H(x^2)}\) ,分子的两个多项式一个只在偶数次处有值,另一个只在奇数次处有值。

所以我们按照 \(n\) 的奇偶性来讨论应该取 \(Q(x)\) 还是 \(P(x)\)。然后得到了规模减小一半的子问题。

最后变成 \([x^0]\frac {F(x)}{G(x)}\),此时计算 \(\frac {f_0}{g_0}\) 就行。

那么这个东西如何解决常系数其次线性递推呢?

常系数其次线性递推,说白了就是给你一个递推式和这个数列的前几项,问你第 \(n\) 项。

众所周知这个是可以矩快 \(O(m^3\log n)\) 的。但是以上算法可以做到 \(O(m\log m\log n)\)虽然一般情况不需要 NTT,所以正常情况下复杂度是 \(O(m^2\log n)\) 的。

首先我们知道斐波那契数列的生成函数是 \(F(x)=\frac 1 {1-x-x^2}\),通过这个我们就可以 \(O(2^2\log n)\) 计算出斐波那契数列的第 \(n\) 项比矩快少三次乘法。

inline int Solve(long long n){
int f0=1,f1=0,g0=1,g1=mod-1,g2=mod-1;
for(;n;n>>=1){
if(n&1)f0=(1ll*g0*f1+1ll*(mod-g1)*f0)%mod,f1=1ll*g2*f1%mod;
else f0=1ll*g0*f0%mod,f1=(1ll*g2*f0+1ll*(mod-g1)*f1)%mod;
g1=(2ll*g0*g2+1ll*(mod-g1)*g1)%mod;g0=1ll*g0*g0%mod;g2=1ll*g2*g2%mod;
}
return 1ll*f0*pow(g0,mod-2)%mod;
}

其实对于正常递推式都可以写成 \(\frac {F(x)}{G(x)}\) 的形式。。。但是不会证。。。

然而我们知道有 \(\frac {F(x)}{G(x)} \equiv H(x) \bmod x^{m+1}\),那么我们就可以知道 \(F(x)=G(x)H(x)\)。

\(G(x)\) 实际上就是这个序列的特征多项式,可以通过 \(1-P(x)\)(\(P(x)\) 是递推式)得到。

inline void times(int*f,int*g,const int&n){
static int sav[M<<1];int i,j;
for(i=0;i<n;++i)for(j=0;j<n;++j)sav[i+j]=(sav[i+j]+1ull*f[i]*g[j])%mod;
for(i=0;i<(n<<1);++i)f[i]=sav[i],sav[i]=0;
}
inline int Solve(int*f,int*g,const int&len,long long n){
static int sav[M<<1];int i;
for(;n;n>>=1){
for(i=0;i<len;++i)sav[i]=g[i],sav[i+len]=0;
for(i=1;i<len;i+=2)sav[i]=mod-sav[i];times(f,sav,len);times(g,sav,len);
for(i=n&1;i<(n<<1);i+=2)f[i>>1]=f[i];
for(i=0;i<(n<<1);i+=2)g[i>>1]=g[i],f[(i>>1)+n]=0;
}
return 1ll*f[0]*pow(g[0],mod-2)%mod;
}

好处?你可以不用推矩阵和调矩阵的那些细节了,并且更快。

坏处?如果模数是非质数那就寄了。但是老算法是不需要模数为质数的

如果有多个序列之间推来推去?如果你是萌新那还是矩阵快速幂吧,如果你是老鸽那可以大力拆得只剩下一个序列,然后化成分式继续 BM。

CF392C?那题直接 \(O(k^2)\) 跑一个暴力求逆不就完了?

2.Berlekamp-Massey

用来猜一个数列的递推式。

如果是数数题然后你状态设错了,但是能够得到正确的答案,然后你又懒得重新设一遍,就可以 BM+BM \(O(m^2\log n)\) 大力草过去。

这个东西和拉格朗日插值有点儿像。

这个 BM 的思想是,我把前几项的递推式都搞出来,并且记录下来,如果我不能由上一项的递推式递推过来,那就通过前面的部分做一些奇怪的操作,然后得到正确的递推式。但实际上我们正常情况下记录的都是最短递推式,所以递推式不一定正确,使用这个 BM 之前建议打表尽量多项,尽管是 \(O(n^2)\) 的

好,我们假设前面的递推式是 \(R_0\) 到 \(R_{cnt-1}\)。

\(delta_i\) 为到第 \(i\) 项之前,上一个递推式在 \(i\) 处的值减去 \(a_i\)。

\(fail_i\) 的意思是 \(R_i\) 在 \(fail_i\) 处失效。

如果 \(delta_i=0\),那么上一个递推式一定是正确的,直接跳过。

否则我们再构造一个递推式,使得这个递推式在前面 \(i-1\) 处的值为 \(0\),在 \(i\) 处的值为 \(delta_i\)。

如何得到这个递推式?

如果我前面一个递推式都没有,那么这个递推式一定是一车 \(0\) 后面跟了一个 \(1\)。

否则我们构造一个神秘递推式。随便拉一个递推式过来,假设是第 \(x\) 个递推式。

那么我们设 \(t = \frac {delta_i} {delta_{fail_x}}\)。

我们构造:

\[\{ 0,0,...0,t,-t \times R_x[1],-t \times R_x[2],... \}
\]

其中开头有 \(i-fail_x-1\) 个 \(0\)。

于是我们找到 \(fail_x+R[x].len\) 最小的 \(x\) 就能够得到最短递推式啦。

inline int BM(int*a,const int&n){
int i,j,id,tmp,cnt=0;
for(i=0;i^n;++i){
delta[i]=a[i];
if(!cnt){
if(a[i])fail[cnt++]=i,R[cnt].resize(i,0);
continue;
}
delta[fail[cnt]=i]=a[i];
for(j=0;j^R[cnt].size();++j)delta[i]=Del(delta[i],1ll*a[i-j-1]*R[cnt][j]%mod);
if(!delta[i])continue;id=cnt-1;
for(j=0;j^cnt;++j)if(fail[j]-R[j].size()>fail[id]-R[id].size())id=j;
tmp=1ll*delta[i]*pow(delta[fail[id]])%mod;++cnt;R[cnt]=R[cnt-1];
while(R[cnt].size()<i-fail[id]+R[id].size())R[cnt].push_back(0);
R[cnt][i-fail[id]-1]=Add(R[cnt][i-fail[id]-1],tmp);
for(j=0;j^R[id].size();++j){
R[cnt][i-fail[id]+j]=Del(R[cnt][j-fail[id]+i],1ll*tmp*R[id][j]%mod);
}
}
for(i=0,id=R[cnt].size();i^id;++i)p[i+1]=R[cnt][i];
return id;
}

递推式将会存放在 \(p\) 中,长度会由 \(BM()\) 返回。

BM 学习笔记的更多相关文章

  1. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  2. Java学习笔记(04)

    Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...

  3. Android学习笔记(十二)——实战:制作一个聊天界面

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...

  4. input子系统学习笔记六 按键驱动实例分析下【转】

    转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html 本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! i ...

  5. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

  6. Oracle学习笔记之四sp1,Oracle 11g的常用函数

    从Oracle学习笔记之四,SQL语言入门中摘出来的,独立成一章节 3.1 字符类函数 ASCII(c)和CHR(i)    分别用于返回一个字符的ASCII码和返回给定ASCII值所对应的字符. C ...

  7. 23 DesignPatterns学习笔记:C++语言实现 --- 2.4 Composite

    23 DesignPatterns学习笔记:C++语言实现 --- 2.4 Composite 2016-07-22 (www.cnblogs.com/icmzn) 模式理解

  8. 23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter

    23 DesignPatterns学习笔记:C++语言实现 --- 2.2 Adapter 2016-07-22 (www.cnblogs.com/icmzn) 模式理解

  9. 23 DesignPatterns学习笔记:C++语言实现 --- 1.5 Prototype

    23 DesignPatterns学习笔记:C++语言实现 --- 1.5 Prototype 2016-07-21 (www.cnblogs.com/icmzn) 模式理解

随机推荐

  1. 简单模拟Java中反射的应用场景

    有人说Java是一门静态语言.那么何为静态语言,动态语言又是什么? 1.动态语言 是一类在运行时可以改变其结构的语言:例如新的函数.对象.甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化 ...

  2. spring boot 配置静态路径

    一  前言 最近有个项目,需要上传一个zip文件(zip文件就是一堆的html压缩组成)的压缩文件,然后后端解压出来,用户可以预览上传好的文件. 查看资料,spring boot对静态文件,可以通过配 ...

  3. Solution -「洛谷 P5827」边双连通图计数

    \(\mathcal{Description}\)   link.   求包含 \(n\) 个点的边双连通图的个数.   \(n\le10^5\). \(\mathcal{Solution}\)    ...

  4. Solution -「NOI 2016」「洛谷 P1587」循环之美

    \(\mathcal{Description}\)   Link.   给定 \(n,m,k\),求 \(x\in [1,n]\cap\mathbb N,y\in [1,m]\cap \mathbb ...

  5. 如何在 Flutter 中集成华为云函数服务

    介绍 云函数是一项 Serverless 计算服务,提供 FaaS(Function as a Service)能力,可以帮助开发者大幅简化应用开发与运维相关事务,降低应用功能的实现门槛,快速构建业务 ...

  6. k8s基础环境配置:基于CentOS7.9

    k8s基础环境配置:基于CentOS7.9 wmware15安装centos7.9:https://www.cnblogs.com/uncleyong/p/15261742.html 1.配置静态ip ...

  7. loadrunner查看并发产生的错误日志

    有些测试朋友在用lr的时候,遇到错误,不知道怎么从客户端看日志,下面我简单介绍下. 设置日志:仅错误的时候发送 压测过程中报错,点击放大镜 有170个虚拟用户报这个错 下面可以看到虚拟用户编号 在虚拟 ...

  8. python开启httpserver

  9. Meterpreter后渗透阶段关闭防火墙与杀毒软件

  10. 传统式BI工具和自助式BI工具到底有什么区别

    相信很多人都听说过BI工具,但是你听说过自助BI工具吗?自助式BI工具面向没有IT背景的业务分析师,比传统的BI工具灵活易用,在一定程度上摆脱了对IT部门的大幅度依赖,使数据产品链更加大众化,更加理解 ...