关于斐波那契数列
关于斐波那契数列
警告:本文使用了微少的
斐波那契数列的定义
这个是很显然的吧。
例题
P1720 月落乌啼算钱(斐波那契数列)
这一道题是语法的入门题,由于项数不超过
#include<cstdio>
int main(){
int n,n1=1,n2=1,s=0;//第一项和第二项。
scanf("%d",&n);
if (n==1) return printf("%d\n",n1),0;
s=n2;
for (int i=3;i<n;i++){
if (i&1) n1+=n2,s=n1;
else n2+=n1,s=n2;
}
printf("%d\n",s);
return 0;
}
上面的代码时间复杂度是
公式:
证明(虽然我也没看懂):
于是我们就可以利用上面的通项公式,使用 cmath
库中的 sqrt
和 pow
函数来简洁地求解:
//the code is from chenjh
#include<cstdio>
#include<cmath>
int main(){
int n;scanf("%d",&n);
printf("%.2lf\n",1.0/sqrt(5)*(pow((1+sqrt(5))/2,n)-pow((1-sqrt(5))/2,n)));
return 0;
}
上面的代码的时间复杂度是 sqrt
和 pow
函数的时间复杂度
「POJ3070」Fibonacci
此题要求
所以我们就需要——矩阵乘法来加速递推。
斐波那契数列的另外一个通项公式是:
于是我们就可以利用矩阵乘法配合快速幂进行
//the code is from chenjh
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int m=10000;
void mul(int f[2],int a[2][2]){
int c[2];
memset(c,0,sizeof(c));
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c[j]=(c[j]+(LL)f[k]*a[k][j])%m;
memcpy(f,c,sizeof(c));
}
void mulself(int a[2][2]){
int c[2][2];
memset(c,0,sizeof(c));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c[i][j]=(c[i][j]+(LL)a[i][k]*a[k][j])%m;
memcpy(a,c,sizeof(c));
}
int main(){
int n;
while(cin>>n && n!=-1){
int f[2]={0,1};
int a[2][2]={{0,1},{1,1}};
for(;n;n>>=1){
if(n&1) mul(f,a);
mulself(a);
}
cout<<f[0]<<endl;
}
return 0;
}
LibreOJ #10221. 「一本通 6.5 例 3」Fibonacci 前 n 项和
设斐波那契数列的第
方法一
根据矩阵乘法的定义,可以列出公式:
最后利用矩阵乘法配合快速幂实现,时间复杂度为
//the code is from chenjh
#include<cstdio>
#include<cstring>
typedef long long LL;
LL m;
void mul(LL f[3],LL a[3][3]){
LL c[3];
memset(c,0,sizeof(c));
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
c[j]=(c[j]+f[k]*a[k][j])%m;
memcpy(f,c,sizeof(c));
}
void mulself(LL a[3][3]){
LL c[3][3];
memset(c,0,sizeof(c));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
c[i][j]=(c[i][j]+a[i][k]*a[k][j])%m;
memcpy(a,c,sizeof(c));
}
int main(){
LL n;
scanf("%lld%lld",&n,&m);
LL f[3]={0,0,1};
LL a[3][3]={{1,0,0},{0,0,1},{1,1,1}};
for(;n;n>>=1){
if(n&1) mul(f,a);
mulself(a);
}
printf("%lld\n",f[0]);
return 0;
}
方法二
公式:
证明:
运用数学归纳法。
当
时,命题成立。 假设
时,命题成立。 当
时:
所以直接用矩阵乘法配合快速幂求出
时间复杂度
//the code is from chenjh
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL m;
void mul(LL f[2],LL a[2][2]){
LL c[2];
memset(c,0,sizeof(c));
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c[j]=(c[j]+f[k]*a[k][j])%m;
memcpy(f,c,sizeof(c));
}
void mulself(LL a[2][2]){
LL c[2][2];
memset(c,0,sizeof(c));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c[i][j]=(c[i][j]+a[i][k]*a[k][j])%m;
memcpy(a,c,sizeof(c));
}
int main(){
LL n;
scanf("%lld%lld",&n,&m);
n+=2;
LL f[2]={0,1};
LL a[2][2]={{0,1},{1,1}};
for(;n;n>>=1){
if(n&1) mul(f,a);
mulself(a);
}
printf("%lld\n",f[0]-1);
return 0;
}
LibreOJ #10222. 「一本通 6.5 例 4」佳佳的 Fibonacci
计算出前
通项公式是:
于是就可以直接计算了,但是我们仍要证明一下:
把他变成一个三角形:
答案就是这个三角形内所有数之和。
我们可以把这个三角形竖着看,发现了啥?这个式子就是:
把
提取出来: 这个时候,
派上用场了。把这个式子往里面套啊! 发现了啥?
其实也可以转化为 。 把
再往 里面套! 答案就变成了:
//the code is from chenjh
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=(a);i<(b);++i)
typedef long long LL;
int n,m;
void mul(int f[2],int a[2][2]){
int c[2];
memset(c,0,sizeof c);
rep(i,0,2)rep(j,0,2)c[i]=(c[i]+(LL)f[j]*a[j][i])%m;
memcpy(f,c,sizeof c);
}
void mulself(int a[2][2]){
int c[2][2];
memset(c,0,sizeof c);
rep(i,0,2)rep(j,0,2)rep(k,0,2)c[i][j]=(c[i][j]+(LL)a[i][k]*a[k][j])%m;
memcpy(a,c,sizeof c);
}
int main(){
scanf("%d%d",&n,&m);
int f[2]={0,1};
int a[2][2]={{0,1},{1,1}};
for(int x=n+2;x;x>>=1,mulself(a))if(x&1)mul(f,a);
printf("%lld\n",((LL)n*f[0]-f[1]+2+m)%m);
return 0;
}
补充知识
- fib在模m后,一定存在周期性。
- More:斐波那契数列的性质 - Milkor - 博客园 (cnblogs.com)
参考文献
- LaTeX 数学公式大全 - Iowa_BattleShip 的博客 - 洛谷博客 (luogu.com.cn)
- 斐波那契数列的性质 - Milkor - 博客园 (cnblogs.com)
- 题解 - 讨论 - LibreOJ (loj.ac)
本人制作不易,公式可能会有打错的地方,欢迎指出错误,点个赞吧。
标签:
总结
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话