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

具体过程是这样的。

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

  1. 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,然后塞过去。。

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

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

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

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

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

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

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

正确性???

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<vector>
  4. #define N 100009
  5. using namespace std;
  6. typedef long long ll;
  7. const ll mod=;
  8. ll n,f[N],delta[N],fail[N],cnt,last;
  9. vector<ll>cur,now,pre;
  10. inline int rd(){
  11. int x=;char c=getchar();bool f=;
  12. while(!isdigit(c)){if(c=='-')f=;c=getchar();}
  13. while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
  14. return f?-x:x;
  15. }
  16. inline ll power(ll x,ll y){
  17. ll ans=;
  18. while(y){
  19. if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;
  20. }
  21. return ans;
  22. }
  23.  
  24. int main(){
  25. n=rd();
  26. for(int i=;i<=n;++i)f[i]=rd();
  27. for(int i=;i<=n;++i){
  28. delta[i]=mod-f[i];
  29. for(int j=;j<now.size();++j)(delta[i]+=1ll*now[j]*f[i-j-]%mod)%=mod;
  30. if(!delta[i])continue;
  31. fail[cnt]=i;
  32. if(!cnt){now.resize(i);cnt++;continue;}
  33. ll inv=((mod-1ll*delta[i]*power(delta[fail[last]],mod-)%mod)%mod+mod)%mod;
  34. cur.clear();cur.resize(i-fail[last]-);cur.push_back(mod-inv);
  35. for(int j=;j<pre.size();++j)cur.push_back(1ll*pre[j]*inv%mod);
  36. if(now.size()>cur.size())cur.resize(now.size());
  37. for(int j=;j<now.size();++j)(cur[j]+=now[j])%=mod;
  38. if(i-now.size()>=fail[last]-pre.size())pre=now,last=cnt; //fail[last]!!!
  39. cnt++;now=cur;
  40. }
  41. for(int i=;i<now.size();++i)cout<<now[i]<<",";cout<<now.size();
  42. return ;
  43. }

应用

[NOI2007]生成树计数

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

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

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

于是就直接上矩乘。

代码

打表

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #define N 402
  5. using namespace std;
  6. typedef long long ll;
  7. ll a[N][N],n;
  8. const int mod=;
  9. inline ll power(ll x,ll y){
  10. ll ans=;
  11. while(y){
  12. if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;
  13. }
  14. return ans;
  15. }
  16. inline ll ni(ll x){return power(x,mod-);}
  17. inline ll matr(int n){
  18. for(int i=;i<=n;++i){
  19. for(int j=i+;j<=n;++j){
  20. ll x=1ll*a[j][i]*ni(a[i][i])%mod;
  21. for(int k=i;k<=n;++k)a[j][k]=(a[j][k]-x*a[i][k]%mod+mod)%mod;
  22. }
  23. }
  24. ll ans=;
  25. for(int i=;i<=n;++i)ans=ans*a[i][i]%mod;
  26. return ans;
  27. }
  28. int main(){
  29. freopen("out","w",stdout);
  30. int kk=;
  31. for(int n=;n<=;++n){
  32. memset(a,,sizeof(a));
  33. for(int i=;i<=n;++i){
  34. for(int k=i-;k>=&&k>=i-kk;--k)a[i][i]++,a[i][k]--;
  35. for(int k=i+;k<=n&&k<=i+kk;++k)a[i][i]++,a[i][k]--;
  36. }
  37. printf("%lld,",matr(n-));
  38. }
  39. return ;
  40. }

矩阵乘法

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. typedef long long ll;
  6. const int mod=;
  7. ll top,n;
  8. int s1[]={,};
  9. int s2[]={,,,};
  10. int s3[]={,,,,,,,};
  11. int s4[]={,,,,,,,,,,,,,,,,,};
  12. int s5[]={,,,,,,,,,,,,,
  13. ,,,,,,,,,,,,,,
  14. ,,,,,,,,,,,,,,,,,,};
  15. int a1[]={,};
  16. int a2[]={,,,};
  17. int a3[]={,,,,,,,};
  18. int a4[]={,,,,,,,,,,,,,,,,,};
  19. int a5[]={,,,,,,,,,,,,,,,,,,
  20. ,,,,,,,,,,,,,,,,
  21. ,,,,,,,,,,,};
  22. inline ll power(ll x,ll y){
  23. ll ans=;
  24. while(y){if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;}
  25. return ans;
  26. }
  27. struct matrix{
  28. ll a[][];
  29. matrix(){memset(a,,sizeof(a));}
  30. matrix operator *(const matrix &b)const{
  31. matrix c;
  32. for(int i=;i<=top;++i)
  33. for(int j=;j<=top;++j){
  34. for(int k=;k<=top;++k)
  35. (c.a[i][j]+=a[i][k]*b.a[k][j]%mod)%=mod;
  36. }
  37. return c;
  38. }
  39. }ans,Z;
  40. inline void work1(){
  41. puts("");
  42. }
  43. inline void work2(){
  44. if(n<=){printf("%d\n",a2[n]);return;}
  45. for(int i=;i<=;++i){
  46. ans.a[][i]=a2[i];
  47. Z.a[i][]=s2[-i+];
  48. if(i!=)Z.a[i][i-]=;
  49. }
  50. n-=;top=;
  51. while(n){
  52. if(n&)ans=ans*Z;
  53. Z=Z*Z;
  54. n>>=;
  55. }
  56. printf("%lld",ans.a[][]);
  57. }
  58. inline void work3(){
  59. if(n<=){printf("%d\n",a3[n]);return;}
  60. for(int i=;i<=;++i){
  61. ans.a[][i]=a3[i];
  62. Z.a[i][]=s3[-i+];
  63. if(i!=)Z.a[i][i-]=;
  64. }
  65. n-=;top=;
  66. while(n){
  67. if(n&)ans=ans*Z;
  68. Z=Z*Z;
  69. n>>=;
  70. }
  71. printf("%lld",ans.a[][]);
  72. }
  73. inline void work4(){
  74. if(n<=){printf("%d\n",a4[n]);return;}
  75. for(int i=;i<=;++i){
  76. ans.a[][i]=a4[i];
  77. Z.a[i][]=s4[-i+];
  78. if(i!=)Z.a[i][i-]=;
  79. }
  80. n-=;top=;
  81. while(n){
  82. if(n&)ans=ans*Z;
  83. Z=Z*Z;
  84. n>>=;
  85. }
  86. printf("%lld",ans.a[][]);
  87. }
  88. inline void work5(){
  89. if(n<=){printf("%d\n",a5[n]);return;}
  90. for(int i=;i<=;++i){
  91. ans.a[][i]=a5[i];
  92. Z.a[i][]=s5[-i+];
  93. if(i!=)Z.a[i][i-]=;
  94. }
  95. n-=;top=;
  96. while(n){
  97. if(n&)ans=ans*Z;
  98. Z=Z*Z;
  99. n>>=;
  100. }
  101. printf("%lld",ans.a[][]);
  102. }
  103. int main(){
  104. int k;
  105. cin>>k>>n;
  106. if(k==)work1();
  107. else if(k==)work2();
  108. else if(k==)work3();
  109. else if(k==)work4();
  110. else if(k==)work5();
  111. return ;
  112. }

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. Vysor破解助手for Linux and macOS

    <Vysor Pro破解助手>提供了Windows下的Vysor破解工具,为了使用Linux及macOS同学的方便,最近整理了Linux及macOS版的Vysor破解助手. Linux版V ...

  2. java新知识系列 二

      1:数据库事务隔离以及事务隔离的级别 数据库事务隔离: 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别:为了解决更新丢失,脏读,不可重读(包括虚读和幻读)等问题在标准SQL规 ...

  3. 列表、enumerate()函数,以及查看数据类型所有的内置方法

    随便看看 """ forList(): 测试list和enumerate()函数 examineFun(): 查看数据类型所有的内置方法 ""&quo ...

  4. git add 添加多个文件

    在使用git add提交多个文件的方式: git add .   后面加一个".",匹配所有的文件 总结下,提交多个文件时,git add后可以有如下参数以及参数的解释: git ...

  5. LeetCode算法题-Kth Largest Element in a Stream(Java实现)

    这是悦乐书的第296次更新,第315篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第164题(顺位题号是703).设计一个类来查找流中第k个最大元素.请注意,它是排序顺序 ...

  6. 明天研究下jpa直接像django一样生成

    https://blog.csdn.net/yztezhl/article/details/79390714 自动生成 教程-- https://blog.csdn.net/mxjesse/artic ...

  7. MYSQL primary key use btree 是什么含义了解一下

    CREATE TABLE `sth_definition` ( `id` int(11) NOT NULL AUTO_INCREMENT, `analyseId` bigint(20) DEFAULT ...

  8. Exp6 信息搜集与漏洞扫描 20165110

    Exp6 信息搜集与漏洞扫描 20165110 一.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 二.实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描 ...

  9. AI deeplab

    参考链接: https://arxiv.org/pdf/1412.7062v3.pdf

  10. future builder

    import 'package:flutter/material.dart';import 'dart:convert';import 'package:http/http.dart' as http ...