题目背景
大家都知道,斐波那契数列是满足如下性质的一个数列:
• f(1)=1
• f(2)=1
• f(n)=f(n−1)+f(n−2)(n≥2且n为整数)
题目描述
请你求出 f(n) mod 1000000007 的值。
输入格式
第1行:一个整数n
输出格式
第1行:f(n) mod 1000000007 的值
输入样例#1
5
输出样例#1
5
输入样例#2
10
输出样例#2
55
说明
对于 60% 的数据:n≤92。
对于 100% 的数据:n在long long(INT64)范围内。
思路
矩阵乘法优化。(友情提示:一个n×m的矩阵A和一个m×r的矩阵相乘,得出一个n×r的矩阵,这个矩阵的i行j列为∑mk=1,矩阵乘法不满足交换律,但满足结合律和分配律)
首先,斐波那契数列的递推式为fi=fi−1+fi−2,那么设有一个矩阵A:
[fi−1fi−2]
要依据这个矩阵乘上一个矩阵
trans求出另外一个矩阵
B:
[fifi−1]
求这个矩阵
trans。
显然, trans这个矩阵要为
[0111]
才能满足
A×trans=b
那么这样如果暴力做显然是 O(n)的,并没有优化。
考虑到
[f2f1]×[0111]n−2=[fnfn−1]
并且矩阵乘法满足结合律,那么可以用快速幂优化。
最终时间复杂度 O(logn)
代码
#include <cstdio>
const int maxn=10;
const int mo=1000000007;
struct matrix
{
long long a[maxn+1][maxn+1],r,c;
matrix operator *(const matrix &other)
{
matrix res;
res.r=r;
res.c=other.c;
for(int i=1; i<=res.r; i++)
{
for(int j=1; j<=res.c; j++)
{
long long sum=0;
for(int k=1; k<=c; k++)
{
sum+=a[i][k]*other.a[k][j];
sum%=mo;
}
res.a[i][j]=sum;
}
}
return res;
}
};
long long n;
matrix t,c,ans;
matrix quickpow(matrix a,long long b,int m)
{
matrix res;
res.c=a.c;
res.r=a.r;
for(int i=1; i<=res.r; i++)
{
for(int j=1; j<=res.c; j++)
{
res.a[i][j]=0;
}
res.a[i][i]=1;
}
while(b)
{
if(b&1)
{
res=res*a;
b--;
}
b/=2;
a=a*a;
}
return res;
}
inline long long read()
{
long long x=0;
int f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main()
{
n=read();
if(n==1ll)
{
printf("1\n");
return 0;
}
t.r=1;
t.c=2;
t.a[1][1]=1;
t.a[1][2]=1;
c.r=2;
c.c=2;
c.a[1][1]=0;
c.a[1][2]=1;
c.a[2][1]=1;
c.a[2][2]=1;
ans=t*quickpow(c,n-2,mo);
printf("%lld\n",ans.a[1][2]);
return 0;
}