您的位置:首页 > 其它

洛谷P1962 斐波那契数列

2017-10-31 16:41 344 查看
题目背景

大家都知道,斐波那契数列是满足如下性质的一个数列:

• 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: