首先这是一道计数类DP,那我们得先推式子,经过瞎掰乱凑,经过认真分析,我们可以得到这样的方程

F(N)=F(0)+F(1)+....+F(N-M-1)

所有F初值为1,F(1)=2

ANS=F(N+M);

那显然我们有这样的代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int M=1e9+;
using namespace std;
inline int read(){
char chr=getchar(); int f=,ans=;
while(!isdigit(chr)) {if(chr=='-') f=-;chr=getchar();}
while(isdigit(chr)) {ans=(ans<<)+(ans<<);ans+=chr-'';chr=getchar();}
return ans*f;
}
void write(int x){
if(x<) putchar('-'),x=-x;
if(x>) write(x/);
putchar(x%+'');
}int n,m,f[];
int main(){
n=read(),m=read();
f[]=;f[]=;
for(int i=;i<=n+m;i++){
f[i]=;
for(int j=;j<=i-m-;j++)
if(f[i]+f[j]>M) f[i]=f[i]+f[j]-M;
else f[i]=f[i]+f[j];//卡一波时间
}cout<<f[n+m];
return ;
}

显然这是O(n^2)的算法,然而面对N=1e18,这个算法可以去优化见鬼了,这样子由于语句比较简单,勉强可以过十万的数据大概30分

考虑优化:

我们先看一下上面的式子,尝试对这个式子变形...好吧,其实就是迭代,然后用鸽笼原理一通乱搞:

F(N)=F(N-1)+F(N-M-1)

ANS=F(N)

好了我们把这个东西优化得到了O(N)的算法:

期望得分:50pts

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int M=1e9+;
using namespace std;
inline int read(){
char chr=getchar(); int f=,ans=;
while(!isdigit(chr)) {if(chr=='-') f=-;chr=getchar();}
while(isdigit(chr)) {ans=(ans<<)+(ans<<);ans+=chr-'';chr=getchar();}
return ans*f;
}
void write(int x){
if(x<) putchar('-'),x=-x;
if(x>) write(x/);
putchar(x%+'');
}int n,m,f[];
int main(){
n=read(),m=read();
f[]=;f[]=;
for(int i=;i<=n;i++)
f[i]=(f[i-]+f[max(i-m-,)])%M;
cout<<f[n];
return ;
}

考虑继续优化

某个大佬说过1e18的数据考虑logn的算法,比如快速幂。

这既然是DP,那自然往矩阵乘法考虑。

  考虑构造矩阵:m这么小,而且递推式中出现的常量只有m,显然矩阵的大小要往m*m考虑

  m=1的时候斐波那契,显然不用我推了

  看一下其他情况:

  

得到通式(写了的是1,其他是0):

然后会矩阵加速的同学都知道该怎么做了吧...

 // luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
const int M=1e9+;
using namespace std;
inline int read(){
char chr=getchar(); int f=,ans=;
while(!isdigit(chr)) {if(chr=='-') f=-;chr=getchar();}
while(isdigit(chr)) {ans=(ans<<)+(ans<<);ans+=chr-'';chr=getchar();}
return ans*f;
}
void write(int x){
if(x<) putchar('-'),x=-x;
if(x>) write(x/);
putchar(x%+'');
}int n,m;
struct P{int a[][];P(){memset(a,,sizeof(a));}}A,B;
P operator *(const P &x,const P &y){
P ans;
for(int i=;i<m;i++)
for(int k=;k<m;k++)
for(int j=;j<m;j++)
ans.a[i][j]=(ans.a[i][j]+x.a[i][k]*y.a[k][j])%M;
return ans;
}
void KSM(int n){
while(n){
if(n&) B=B*A;
n>>=;A=A*A;
}
}
inline void init(){
n=read(),m=read();--n,++m;
A.a[m-][m-]=A.a[][m-]=;
for(int i=;i<m-;i++) A.a[i+][i]=;//初始矩阵
for(int i=;i<m;i++)B.a[][i]=i+;
}
signed main(){
init();KSM(n);
write(B.a[][]);
return ;
}

最新文章

  1. java的继承练习
  2. Oozie 快速入门
  3. 移动端touch模块
  4. MVC。Action方法,常用的返回类型有几种?
  5. dom4j解析xml作为测试数据
  6. C++ shared_ptr deleter的实现
  7. 【NOIP2008】双栈排序
  8. 在Ubuntu下ADT识别不出真机的解决办法
  9. java链接mysql数据库
  10. unity中.meta提交错误操作导致空脚本
  11. mybatis中#和$符号的区别(转)
  12. zookeeper leader选举算法源码
  13. 第 16 章 C 预处理器和 C 库(直角坐标转换极坐标)
  14. SNF快速开发平台MVC-Grid++集成打印
  15. 【C++】cmdline——轻量级的C++命令行解析库
  16. sublime3 docblocker插件定制自己的注释,配置步骤
  17. NBU 还原LINUX ORACLE数据库(CRM)
  18. System.Transactions事务超时设置
  19. jquery datatables 学习笔记
  20. Linux sync命令的作用分析

热门文章

  1. privot函数使用
  2. Promise嵌套问题/async await执行顺序
  3. java 导入导出的 命令
  4. 【Android】一个好用的sharedpreferences存储类方法
  5. PAT 1098. Insertion or Heap Sort
  6. SIM900A 发送AT+CSTT 总是 返回Error的原因分析
  7. [转]十五天精通WCF——第六天 你必须要了解的3种通信模式
  8. 查看TEMP 表空间usage
  9. 关于创建Android Library所须要知道的一切
  10. cat&lt;&lt;EOF获取标准输入到文件中