题目背景
大家都知道,斐波那契数列是满足如下性质的一个数列:
F n = 1 ( n ≤ 2 ) F_n= 1 (n≤2) Fn=1(n≤2)
F n − 1 + F n − 2 ( n ≥ 3 ) F_{n−1} +F_{n−2}(n≥3) Fn−1+Fn−2(n≥3)
题目描述
请你求出 F n F_n Fn m o d mod mod 1 0 9 + 7 10^9+7 109+7的值。
输入格式
一行一个正整数 n n n
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1
5
输出 #1
5
输入 #2
10
输出 #2
55
学校OJ:
题目要求一致 m o d mod mod改为 10000 10000 10000
Sample Input
123456789
Sample Output
4514
分析:
已知 f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn−1+fn−2
考虑原有 1 ∗ 2 1*2 1∗2矩阵 f i − 2 f i − 1 f_{i-2} f_{i-1} fi−2fi−1
我们希望通过一个矩阵 反复乘它 来递推出后面的项
也就是希望乘这个矩阵后
f i − 1 , f i = f i − 1 , f i − 2 + f i − 1 f_{i-1},f_{i}=f_{i-1},f_{i-2}+f_{i-1} fi−1,fi=fi−1,fi−2+fi−1
得出这个矩阵 b a s e base base为
0 , 1 0,1 0,1
1 , 1 1,1 1,1
矩阵乘法结合律 得出
[ f 1 , f 2 ] ∗ b a s e n − 1 = [ f n , f n − 1 ] [f_1,f_2]*base^{n-1}=[f_n,f_{n-1}] [f1,f2]∗basen−1=[fn,fn−1]
所以要求的 f n f_n fn就是第一项
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int mod=1e9+7;
long long n;
struct matrix{
long long n,m;
long long G[11][11];
}base,A,B;
matrix operator *(matrix a,matrix b)
{
matrix C;
C.n=a.n;C.m=b.m;
for(int i=1;i<=C.n;i++)
for(int j=1;j<=C.m;j++)
C.G[i][j]=0;
for(int k=1;k<=a.m;k++)
for(int i=1;i<=a.n;i++)
for(int j=1;j<=b.m;j++)
C.G[i][j]=(C.G[i][j]+a.G[i][k]*b.G[k][j]%mod)%mod; //矩阵乘法
return C;
}
void ksm(long long x){
//矩阵快速幂
if(x==1){
A=base;
return;
}
ksm(x/2);
A=A*A;
if(x&1) A=A*base;
}
int main(){
scanf("%lld",&n);
base.n=2;base.m=2;
base.G[1][1]=0;base.G[1][2]=1;
base.G[2][1]=1;base.G[2][2]=1;
if(n<=2){
printf("1");
return 0;
}
else{
B.m=2;B.n=1;
B.G[1][1]=1;B.G[1][2]=1;
ksm(n-1);
B=B*A;
printf("%lld",B.G[1][1]);
}
return 0;
}
一种数学方法求 F n F_n Fn 和矩阵乘法一样的效果
CODE:
#include<cstdio>
#include<iostream>
#include<map>
using namespace std;
map<long,long>F;
long long n;
const long long mod=10000;
long long f(long long n){
if(F.count(n)) return F[n];
long long k=n/2;
if(n%2==0)
{
// n=2*k
return F[n]=(f(k)*f(k)+f(k-1)*f(k-1))%mod;
}else{
// n=2*k+1d
return F[n]=(f(k)*f(k+1)+f(k-1)*f(k))%mod;
}
}
int main(){
F[0]=F[1]=1;
scanf("%lld",&n);
printf("%lld",n==0?0:f(n-1))%mod;
}