一种nb算法,可以求出数列的递推式。

具体过程是这样的。

我们先假设它有一个递推式,然后按位去算他的值。

for(int j=;j<now.size();++j)(delta[i]+=1ll*now[j]*f[i-j-]%mod)%=mod;

这是我们算出了f[i]应当是多少,但是f[i]有可能不是我们算出的值,所以我们记录一个delta,为我们算出的值减去f[i]的结果。

然后查看一下之前有没有出过锅。

如果出过,那么就补一个0,然后塞过去。。

if(!cnt){now.resize(i);cnt++;continue;}

cnt记录出锅次数,now记录当前递推式。

然后我们需要构造一个递推式把这一位的delta补上。

然后我们设inv为这一次的dalta除以上一次的delta。

然后我们的递推式就是在last和now之间补0,然后加一个inv,后面把所有的pre*(-inv)加进去,这样最后n这个位置会出现-delta就满足我们的要求了。

最后我们把构造递推式和当前递推式加起来。

再贪心选一个左端点最靠右的出锅递推式作为last。

正确性???

代码

#include<iostream>
#include<cstdio>
#include<vector>
#define N 100009
using namespace std;
typedef long long ll;
const ll mod=;
ll n,f[N],delta[N],fail[N],cnt,last;
vector<ll>cur,now,pre;
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline ll power(ll x,ll y){
ll ans=;
while(y){
if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;
}
return ans;
} int main(){
n=rd();
for(int i=;i<=n;++i)f[i]=rd();
for(int i=;i<=n;++i){
delta[i]=mod-f[i];
for(int j=;j<now.size();++j)(delta[i]+=1ll*now[j]*f[i-j-]%mod)%=mod;
if(!delta[i])continue;
fail[cnt]=i;
if(!cnt){now.resize(i);cnt++;continue;}
ll inv=((mod-1ll*delta[i]*power(delta[fail[last]],mod-)%mod)%mod+mod)%mod;
cur.clear();cur.resize(i-fail[last]-);cur.push_back(mod-inv);
for(int j=;j<pre.size();++j)cur.push_back(1ll*pre[j]*inv%mod);
if(now.size()>cur.size())cur.resize(now.size());
for(int j=;j<now.size();++j)(cur[j]+=now[j])%=mod;
if(i-now.size()>=fail[last]-pre.size())pre=now,last=cnt; //fail[last]!!!
cnt++;now=cur;
}
for(int i=;i<now.size();++i)cout<<now[i]<<",";cout<<now.size();
return ;
}

应用

[NOI2007]生成树计数

正解貌似是插头dp+快速幂。

然后我们发现k非常小。。。。

那么就可以对于每一个k打一个表,然后再扔到BM里跑一下,发现转移式子最大只有45。

于是就直接上矩乘。

代码

打表

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 402
using namespace std;
typedef long long ll;
ll a[N][N],n;
const int mod=;
inline ll power(ll x,ll y){
ll ans=;
while(y){
if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;
}
return ans;
}
inline ll ni(ll x){return power(x,mod-);}
inline ll matr(int n){
for(int i=;i<=n;++i){
for(int j=i+;j<=n;++j){
ll x=1ll*a[j][i]*ni(a[i][i])%mod;
for(int k=i;k<=n;++k)a[j][k]=(a[j][k]-x*a[i][k]%mod+mod)%mod;
}
}
ll ans=;
for(int i=;i<=n;++i)ans=ans*a[i][i]%mod;
return ans;
}
int main(){
freopen("out","w",stdout);
int kk=;
for(int n=;n<=;++n){
memset(a,,sizeof(a));
for(int i=;i<=n;++i){
for(int k=i-;k>=&&k>=i-kk;--k)a[i][i]++,a[i][k]--;
for(int k=i+;k<=n&&k<=i+kk;++k)a[i][i]++,a[i][k]--;
}
printf("%lld,",matr(n-));
}
return ;
}

矩阵乘法

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=;
ll top,n;
int s1[]={,};
int s2[]={,,,};
int s3[]={,,,,,,,};
int s4[]={,,,,,,,,,,,,,,,,,};
int s5[]={,,,,,,,,,,,,,
,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,};
int a1[]={,};
int a2[]={,,,};
int a3[]={,,,,,,,};
int a4[]={,,,,,,,,,,,,,,,,,};
int a5[]={,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,
,,,,,,,,,,,};
inline ll power(ll x,ll y){
ll ans=;
while(y){if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;}
return ans;
}
struct matrix{
ll a[][];
matrix(){memset(a,,sizeof(a));}
matrix operator *(const matrix &b)const{
matrix c;
for(int i=;i<=top;++i)
for(int j=;j<=top;++j){
for(int k=;k<=top;++k)
(c.a[i][j]+=a[i][k]*b.a[k][j]%mod)%=mod;
}
return c;
}
}ans,Z;
inline void work1(){
puts("");
}
inline void work2(){
if(n<=){printf("%d\n",a2[n]);return;}
for(int i=;i<=;++i){
ans.a[][i]=a2[i];
Z.a[i][]=s2[-i+];
if(i!=)Z.a[i][i-]=;
}
n-=;top=;
while(n){
if(n&)ans=ans*Z;
Z=Z*Z;
n>>=;
}
printf("%lld",ans.a[][]);
}
inline void work3(){
if(n<=){printf("%d\n",a3[n]);return;}
for(int i=;i<=;++i){
ans.a[][i]=a3[i];
Z.a[i][]=s3[-i+];
if(i!=)Z.a[i][i-]=;
}
n-=;top=;
while(n){
if(n&)ans=ans*Z;
Z=Z*Z;
n>>=;
}
printf("%lld",ans.a[][]);
}
inline void work4(){
if(n<=){printf("%d\n",a4[n]);return;}
for(int i=;i<=;++i){
ans.a[][i]=a4[i];
Z.a[i][]=s4[-i+];
if(i!=)Z.a[i][i-]=;
}
n-=;top=;
while(n){
if(n&)ans=ans*Z;
Z=Z*Z;
n>>=;
}
printf("%lld",ans.a[][]);
}
inline void work5(){
if(n<=){printf("%d\n",a5[n]);return;}
for(int i=;i<=;++i){
ans.a[][i]=a5[i];
Z.a[i][]=s5[-i+];
if(i!=)Z.a[i][i-]=;
}
n-=;top=;
while(n){
if(n&)ans=ans*Z;
Z=Z*Z;
n>>=;
}
printf("%lld",ans.a[][]);
}
int main(){
int k;
cin>>k>>n;
if(k==)work1();
else if(k==)work2();
else if(k==)work3();
else if(k==)work4();
else if(k==)work5();
return ;
}

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

  1. Berlekamp_Massey 算法 (BM算法) 学习笔记

    原文链接www.cnblogs.com/zhouzhendong/p/Berlekamp-Massey.html 前言 BM算法用于求解常系数线性递推式. 它可以在 $O(n^2)$ 的时间复杂度内解 ...

  2. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

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

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

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  6. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  7. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

  8. R语言实现关联规则与推荐算法(学习笔记)

    R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...

  9. 二次剩余Cipolla算法学习笔记

    对于同余式 \[x^2 \equiv n \pmod p\] 若对于给定的\(n, P\),存在\(x\)满足上面的式子,则乘\(n\)在模\(p\)意义下是二次剩余,否则为非二次剩余 我们需要计算的 ...

随机推荐

  1. 通过Excel文件快速创建页面和数据表

    在设计一个软件系统,构建过程:需求->数据表->系统开发.实际情况是需求(数据)很多来源于已经存在的文件中,客户会要求把这些数据“电子化”,这就给需求分析产生了很大的工作量: 分析这些原始 ...

  2. 动态更新Icon

    动态更改图标主要用到activity-alias和PackageManager的setComponentEnabledSetting方法.具体步骤如下: 1.在AndroidManifest.xml中 ...

  3. 从0开始的Python学习001快速上手手册

    假设大家已经安装好python的环境了. Windows检查是否可以运行python脚本 Ctrl+R 输入 cmd 在命令行中输入python 如果出现下面结果,我们就可以开始python的学习了. ...

  4. Java 位运算符和 int 类型的实现

    Java 位运算符和 int 类型的实现 其他运算符 # 算术运算符 +.-.*./.++i.i++.--i.i-- # 关系运算符 ==.!=.>.<.>=.<= # 逻辑运 ...

  5. centos7搭建ftp

    1.检查安装vsftpd软件 rpm –qa |grep vsftpd 这里显示已经安装了,我们来卸载它重新安装 卸载vsftpd命令 rpm –e 文件名 显示卸载完成 安装vsftpd命令 Yum ...

  6. docker 基础

    概述 起源 2013 年由 DotCloud 公司开源出来的容器管理工具 DotCloud 公司是一家 PAAS 服务提供商,从 docker 的出身也可以看出它的主要功能和方向 技术原理 开始时是基 ...

  7. 记录Vim常用命令

    命令 简单说明 i 进入编辑模式,光标在原位置 I 进入编辑模式,光标在行首位置 o 从光标所在行,下面一行开始编辑 O 从光标所在行,上面一行开始编辑 a 从光标当前字符后编辑 A 从光标所在行的行 ...

  8. jquery中数组对象下面的属性名名是动态的如何获取

    <script> let normalListData = []; function temp() { for (var i = 0; i < 10; i++) { let rowC ...

  9. java 下载word freemaker

    网上有很多优质的博文了,这里这篇博客就是记录一下字自己,写demo的历程,坑和收获 在java程序中下载word 有6中方式,此处省略(嘻嘻),不过大家公认的是 freemaker 和 PageOff ...

  10. fliplr函数

    fliplr  左右翻转矩阵 语法: B = fliplr(A) 将矩阵A的列绕垂直轴进行左右翻转 matabc 如果A是一个行向量,fliplr(A)将A中元素的顺序进行翻转. 如果A是一个列向量, ...