首页 > 编程知识 正文

斐波那契数列的矩阵表示,斐波那契数列矩阵求法

时间:2023-05-05 08:20:45 阅读:264889 作者:2993

矩阵快速幂模板:

#include<bits/stdc++.h>using namespace std;#define ll long long#define mod 1000000007struct matrix{ll cell[5][5];matrix(ll a=0,ll b=0,ll c=0,ll d=0){cell[0][0]=a;cell[0][1]=b;cell[1][0]=c;cell[1][1]=d;}}one(1,1,1,0);matrix mul(matrix a,matrix b){matrix r;for(int i=0;i<2;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++){r.cell[i][j]+=a.cell[i][k]*b.cell[k][j]%mod;r.cell[i][j]=r.cell[i][j]%mod;}return r;}matrix matrixpow(ll k){matrix r(1,0,0,1);matrix cm(1,1,1,0);while(k){if(k&1)r=mul(r,cm);cm=mul(cm,cm);k>>=1;}return r;}int main(){ll n;cin>>n;matrix t=matrixpow(n-1);cout<<t.cell[0][0]<<endl;return 0; }

聊矩阵快速幂原理之前,我先聊聊结构体内置函数。
在工程代码中,结构体通常用于定义“纯数据”类型,只包含较少的辅助成员函数,而用class定义“拥有复杂行为”的类型。
成员函数我至今为止见过两种。
第一种:

#include<bits/stdc++.h>using namespace std;struct AC{int a,b;void find(void)cout<<a<<' '<<b<<endl;}s;int main(){cin>>s.a>>s.b;s.find();return 0; }

这种实际上就是用一个结构体保存一个函数,之后通过使用结构体来使用这个函数。并且这个结构体内的函数时可以使用该结构体里面的”纯数据“的。
第二种:

struct point{ int x,y; point(int x=0,int y=0) { x=x;y=y; }};

在结构体point里定义了一个函数,函数名也叫point,但没有返回值。这样的函数称为构造函数。构造函数是在声明变量时调用的,例如:声明point a,b(1,2)时,分别调用了point()和point(1,2)。注意这个构造函数的两个参数后面都有“=0”字样,其中0为默认值。也就是说,如果没有指明这两个参数的值,就按0处理,因此point()相当于point(0,0)。

现在我们回到此题代码:

struct matrix{ll cell[5][5];matrix(ll a=0,ll b=0,ll c=0,ll d=0){cell[0][0]=a;cell[0][1]=b;cell[1][0]=c;cell[1][1]=d;}}one(1,1,1,0);

用计算机表示矩阵,我们通常使用n维数组。
所以我们要在开始的时候定义一个cell[][]二维数组用于存数据。
在这之后再构造一个函数用于传参,输入值。

现在进入正题,先聊聊矩阵快速幂求斐波那契数列的基本原理:
原理如图:

求斐波那契数列,如果用暴力的解法,即通过前两项来求每一项。这样做当数据过大的时候就会导致超时。而使用矩阵快速幂来计算斐波那契数列就可以极大的减少运算次数,从而达到时间优化。

这种代码的核心时矩阵快速幂:

matrix mul(matrix a,matrix b){matrix r;for(int i=0;i<2;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++){r.cell[i][j]+=a.cell[i][k]*b.cell[k][j]%mod;r.cell[i][j]=r.cell[i][j]%mod;}return r;}matrix matrixpow(ll k){matrix r(1,0,0,1);matrix cm(1,1,1,0);while(k){if(k&1)r=mul(r,cm);cm=mul(cm,cm);k>>=1;}return r;}

我们分别聊一下这两个板块,矩阵乘法板块和快速幂板块。
number 1:

matrix mul(matrix a,matrix b){matrix r;for(int i=0;i<2;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++){r.cell[i][j]+=a.cell[i][k]*b.cell[k][j]%mod;r.cell[i][j]=r.cell[i][j]%mod;}return r;}

矩阵乘法如果不会的自行百度,这里不做解释。
我们看看该子函数的构造
matrix (该函数的返回值是一个matrix类的结构题)mul(函数名)(matrix a(一个参数是matrix类的结构体),matrix b(另一个参数也是matrix结构体))

matrix r (定义一个matrix类的结构体 r ,r是输出结构体)

for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) { }

三个for循环用于实现矩阵乘法。
return r 最后返回矩阵a和b相乘后的结果。

number2 :

matrix matrixpow(ll k){matrix r(1,0,0,1);matrix cm(1,1,1,0);while(k){if(k&1)r=mul(r,cm);cm=mul(cm,cm);k>>=1;}return r;}

这个就是矩阵快速幂的精髓了。
我们要求矩阵 P 的 n-1 次方暴力解就要只是进行n-1次预算(不包括算连个矩阵之间的运算)
但如果用快速幂的化。
我们把 n 用二进制表达出来,上线就是64位数,所以最多进行64次运算,再够大的情况下,快速幂是很高效的。
过程如下:
如果我们要求P的n次方。
在计算机内部,所有的数都是以二进制的形式存储的,所以n可以用某一二进制来表示。
n&1 就是用于判断这一位取或不去,如果是1就取,如果是0就跳。
快速幂里面一定要注意

cm=mul(cm,cm);

即每次右移一位之后就要pow一下。这里不能漏!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。