【SSL 1529】[洛谷P1962]斐波那契数列【矩阵乘法】

题目背景

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

F n = 1 ( n ≤ 2 ) F_n= 1 (n≤2) Fn=1(n2)

F n − 1 + F n − 2 ( n ≥ 3 ) F_{n−1} +F_{n−2}(n≥3) Fn1+Fn2(n3)

题目描述

请你求出 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

扫描二维码关注公众号,回复: 12302962 查看本文章
123456789

Sample Output

4514

分析:

已知 f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2
考虑原有 1 ∗ 2 1*2 12矩阵 f i − 2 f i − 1 f_{i-2} f_{i-1} fi2fi1
我们希望通过一个矩阵 反复乘它 来递推出后面的项
也就是希望乘这个矩阵后
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} fi1,fi=fi1,fi2+fi1
得出这个矩阵 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]basen1=[fn,fn1]
所以要求的 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;
}

猜你喜欢

转载自blog.csdn.net/dgssl_xhy/article/details/111058830
今日推荐