在数学上,斐波那契数列以如下被以递推的方法定义:
F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)。
由以上推理公式,可以求得任何一项的斐波那契数列值。
弊端:斐波那契的值必须是由前两项推导而来,因此算F[n],一定是从F[1]开始算到F[n-1],F[n-2]为止。那么当数值范围很大时候,那么必然会TLE。
这里介绍一种方法用来解决这种问题:矩阵乘法
简要介绍一下矩阵乘法的知识:(读者应该具备矩阵的基础知识....)
我们用Ai,j表示矩阵A的第i行第j列位置上的元素
有矩阵:An,m Bm,k C=A*B=Cn,k
矩阵C中第i行第j列的元素为矩阵A的第i行与矩阵B的第j列的对应位置的数分别相乘后的和
当然,我们需要会求矩阵n次幂:为什么?
因为:在很多问题中,我们在处理递推公式或者动态规划的转移方程时,第i项的值可以由之前的k项推得:即:
我们还需要构造一个矩阵使得满足这个公式:
有:
再转换一下:
这里具体给一个题目解释一下:因为关于矩阵乘法,如果读者需要,我就专门写一遍矩阵乘法的知识讲解吧。这里简要的讲一下就行啦。
题目选自:http://oj.daimayuan.top/course/22/problem/1045
代码:
//基础模板
#include <bits/stdc++.h>
using namespace std;
const int P=1e9+7;
const int N=2;
long long a[N+1][N+1];
long long f[N+1];
int k,n=2;
void aa(){//矩阵幂:A*A=A^2
long long w[N+1][N+1];//用w数组临时记录A^2的矩阵
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
if(a[i][k])
for(int j=1;j<=n;j++)
if(a[k][j])
w[i][j]+=a[i][k]*a[k][j],w[i][j]%=P;
memcpy(a,w,sizeof(a));//copy一遍,用A^2矩阵替代A矩阵
}
void fa(){//f数组 * 矩阵A :公式推导
long long w[N+1];
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
w[i]+=f[j]*a[j][i];
w[i]%=P;
}
}
memcpy(f,w,sizeof(f));
}
void matrixpow(int k){//矩阵快速幂//跟常数快速幂具备同等思想
while(k){
if(k&1) fa();
aa();
k>>=1;
}
}
int main(){
cin>>k;
f[1]=0;f[2]=1;
//构造的A矩阵
a[1][1]=0;a[1][2]=1;
a[2][1]=1;a[2][2]=1;
//
matrixpow(k-1);//进行k-1次
cout<<f[2];//根据推导公式:f[1]=n-1 f[2]=n
}