斐波那契数列
定义:
满足上面的通项公式的数列就叫斐波那契数列
通项公式:
斐波那契通项公式的求法有很多,高中阶段可以用特征根法解决,我们介绍矩阵相似对角化的方法:
首先,我们先根据通项公式构造出下面的方程:
令:
我们规定:
我们可以得到:
要解决矩阵的幂的问题,我们自然而然地想到相似对角化
我们先求出A的特征值:
解出特征向量:
令:
得到:
于是:
利用λ1+λ2=1,可以计算出上式,得到通项公式为:
前n项和相关的结论:
我们写出下面一系列式子:
累加得:
移项整理得:
可见,想要求斐波那契数列的和,归根结底还是求出相应的项
矩阵快速幂
我们可以实现一个矩阵快速幂,来快速地求出对应的斐波那契数列
我们先来实现矩阵乘法运算:
void matmul(int c[][2],int a[][2],int b[][2]){
int temp[2][2]={0};
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
temp[i][j]=(temp[i][j]+a[i][k]*b[k][j]);
}
}
}
memcpy(c,temp,sizeof temp);
}
再仿照快速幂的方法写出矩阵快速幂:
void matpow(int r[][2],int a[][2],int p){
int temp[2][2]={
{1,0},
{0,1}
};
while(p){
if(p&1)matmul(temp,temp,a);
matmul(a,a,a);
p>>=1;
}
memcpy(r,temp,sizeof temp);
}
如此,我们就有了计算斐波那契数列的利器!
小试牛刀:
例题:
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
int n,m;
void matmul(int c[][2],int a[][2],int b[][2]){
int temp[2][2]={0};
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
temp[i][j]=(temp[i][j]+(ll)a[i][k]*b[k][j])%m;
}
}
}
memcpy(c,temp,sizeof temp);
}
void matpow(int r[][2],int a[][2],int p){
int temp[2][2]={
{1,0},
{0,1}
};
while(p){
if(p&1)matmul(temp,temp,a);
matmul(a,a,a);
p>>=1;
}
memcpy(r,temp,sizeof temp);
}
int main(){
cin>>n>>m;
if(m==1){
cout<<"0"<<endl;
return 0;
}
int a[2][2]={
{1,1},
{1,0}
};
matpow(a,a,n);
cout<<(a[0][0]+a[0][1])%m-1<<endl;
return 0;
}