矩阵快速幂 求解斐波那契数列的快速算法

矩阵快速幂模板:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
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);
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一下。这里不能漏!

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值