矩阵乘法
求斐波那契数列第n项谁都会,但是这里n有long long , O(n) 推显然是不行的。于是我们就需要考虑使用矩阵快速幂优化。
构造一个矩阵
[ f[n−1]f[n] ]
,
再构造一个变换矩阵,使得
[ f[n−2]f[n−1] ]×x=[ f[n−1]f[n] ]
很显然x是2*2的矩阵。不妨设 x=[acbd]
那么有如下等式:
[ f[n−2]f[n−1] ]×[acbd]=[ f[n−1]f[n] ]
根据矩阵乘法,可以得到各项系数:
x=[0111]
根据矩乘的结合率,我们可以得到:
[ f[1]f[2] ]×[0111]n−2=[ f[n−1]f[n] ]
于是我们就可以用快速幂在 O(log2n) 的时间得到第n项了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
struct Matrix{
int n,m;
LL a[3][3];
}a,b;
LL n;
Matrix operator * (const Matrix &x,const Matrix &b){
Matrix c;
c.n=x.n,c.m=b.m;
for (int i=1;i<=c.n;i++)
for (int j=1;j<=c.m;j++){
c.a[i][j]=0;
for (int k=1;k<=x.m;k++)
(c.a[i][j]+=x.a[i][k]*b.a[k][j])%=MOD;
}
return c;
}
Matrix ksm(Matrix a,LL b){
Matrix ret;
ret.m=ret.n=2;
for (int i=1;i<=ret.n;i++)
for (int j=1;j<=ret.m;j++)
ret.a[i][j]=1;
while (b){
if (b&1) ret=ret*a;
b>>=1; a=a*a;
}
return ret;
}
int main(){
scanf("%lld",&n);
if (n==1) return printf("1\n"),0;
b.a[1][1]=0; b.a[1][2]=1;
b.a[2][1]=1; b.a[2][2]=1;
b.n=b.m=2;
a.a[1][1]=0; a.a[1][2]=1;
a.n=1,a.m=2;
printf("%lld\n",(a*ksm(b,n-2)).a[1][2]);
return 0;
}