矩阵快速幂与斐波那契数列
首先先说斐波那契数列,我们都知道它的递推式子是
n>=2 时f[n] = f[n-1]+f[n-2]
n = 1 时 f[1] = 1
n = 0 时 f[0] = 0
当题目让我们求一个斐波那契数列,比如n = 1000时,它变得非常大,所以通常题目会让我们求f[n]%mod。这样还能继续用递推做,但是……
当1<=n <= 1e9时,我们无法开这么大的数组,即使使用vector,o(n)的递推算法,也会让时间超限。那么,我们怎么从空间和时间上来求这么大的斐波那契数列呢?
首先你要具备线性代数中矩阵的有关知识~
矩阵的概念,性质,矩阵乘法等
知道矩阵乘法是怎么求得,那么代码怎么写呢?
比如有两个个矩阵A[m][t], B[t][n] = C[m][n]
代码:矩阵乘法
#include<bits/stdc++.h>
using namespace std;
struct mat
{
int a[15][15];
mat(){ //重载
memset(a,0,sizeof(a));
}
};
mat mul(mat x,mat y,int m,int n,int t)
{
mat res;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<t;k++)
{
res.a[i][j] += x.a[i][k]*y.a[k][j];
}
}
}
return res;
}
int main()
{
mat x,y;
int m = 2,n=2,t = 3; // 矩阵a[m][t]*b[t][n]
for(int i=0;i<m;i++)
{
for(int j=0;j<t;j++)
cin>>x.a[i][j];
}
for(int i=0;i<t;i++)
{
for(int j=0;j<n;j++)
cin>>y.a[i][j];
}
mat tmp = mul(x,y,m,n,t);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
cout<<tmp.a[i][j]<<" ";
cout<<endl;
}
return 0;
}
那么对于矩阵乘法与递推式之间的关系:
如:斐波那契数列
n>=2 时f[n] = f[n-1]+f[n-2]
n = 1 时 f[1] = 1
n = 0 时 f[0] = 0
证明:
我们把几个递推式写成以下形式:
f[n+1] = 1 * f[n] + 1 * f[n-1];
f[n] = 1 * f[n] + 0 * f[n-1];
f[n] = 1 * f[n-1] + 1 * f[n-2];
f[n-1] = 1 * f[n-1] + 0 * f[n-2];
我们把上述表达式转换成矩阵乘法
- 式:
= X
同理
- 式:
= X
我们把②式带入①式
得
= X
我们发现右式子左边的幂p和右边矩阵左上角的f[]的下标s具有关系 p+s = n+1
如:上式的2和n-1, n-1+2 = n+1 所以我们能通过这个恒关系,推出
结论:
= X
= (注:f[1]=f[2] = 1, f[0] = 0)
哇~(ノ>ω<)ノ 我们发现通过求这个矩阵的n次方,就可以知道f[n]啦!
这里我就把推出来的 成为 基础矩阵 (个人习惯)
所以代码如下:d(d'∀')
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int M = 1e9+7;
typedef long long ll;
const int mod = 1e9+7;
int n ;
struct mat
{
ll a[15][15];
mat(){ //重载
memset(a,0,sizeof(a));
}
};
mat mul(mat x,mat y)
{
mat res;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
res.a[i][j] = (res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
return res;
}
ll qpow(int p)
{
mat bas;//基础矩阵
mat res;//单位矩阵
for(int i=0;i<2;i++)
res.a[i][i] = 1;
bas.a[0][0] = bas.a[0][1] = bas.a[1][0] = 1;
bas.a[1][1] = 0;
while(p)
{
if(1&p) res = mul(res,bas);
bas = mul(bas,bas);
p>>=1;
}
return res.a[0][1];//或者res.a[1][0]
}
int main()
{
cin>>n;
cout<<qpow(n)<<endl; //f[n] = qpow(n)
return 0;
}