POJ3070 Fibonacci(斐波那契数列、矩阵快速幂)

题目链接

Description

In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

An alternative formula for the Fibonacci sequence is

.

Given an integer n, your goal is to compute the last 4 digits of Fn.

Input

The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.

Output

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

Sample Input

0
9
999999999
1000000000
-1

Sample Output

0
34
626
6875

Hint

As a reminder, matrix multiplication is associative, and the product of two 2 × 2 matrices is given by

.

Also, note that raising any 2 × 2 matrix to the 0th power gives the identity matrix:

.

求斐波那契数列的第n项mod10000

这里总结下斐波那契数列的求法:
1、直接递归求解,利用公式f(n)=f(n-1)+f(n-2),递归出口是f(0)=0,f(1)=1;

int f(int n)//忽略精度

{
	if(n==0) return 0;
	else if(n==1) return 1;
	return f(n-1)+f(n-2);
}


2、自底向上实现,保存中间值,避免冗余计算,f[n]=f[n-1]+f[n-2],f[0]=0,f[1]=1;

//也可不利用数组,只利用两个值亦可
f[0]=0;f[1]=1;
for(int i=2;i<=n;i++)
f[i]=f[i-1]+f[i-2];


3、比内公式实现,f[n]=\frac{1}{\sqrt{5}}[(\frac{1+\sqrt{5}}{2})^n-\frac{1-\sqrt{5}}{2})^n]

//精度不够,会有偏差
double a=(1+sqrt(5))/2;
double b=(1-sqrt(5))/2;
for(int i=0;i<=n;i++)
f[i]=(pow(a,i)-pow(b,i))/sqrt(5);

4、矩阵乘法实现,这题很贴心的给出了用矩阵求的表达式

亦可如下推导
 

整数快速幂可参考https://www.cnblogs.com/wangzhebufangqi/p/12796176.html
矩阵快速幂可参考https://www.cnblogs.com/cmmdc/p/6936196.html

回到这题。AC代码:

//CSDN博客:https://blog.csdn.net/qq_40889820
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<map>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define random(a,b) (rand()%(b-a+1)+a)
#define ull unsigned long long
#define e 2.71828182
#define Pi 3.141592654
using namespace std;
class matrix
{
	private:
		int **body;//二维矩阵
		int m,n;//m行n列 
	public:
		matrix(int M,int N)//构造函数,动态开辟二维数组 
		{
			m=M;n=N;
			body=new int*[M];
			for(int i=0;i<M;i++) 
				body[i]=new int[N]();
		}
		void assign(int M,int N,int num) {body[M][N]=num;}//赋值
		matrix multi(matrix x,int mod);//矩阵乘法 
		matrix QuickPower(ull n,int mod);//矩阵快速幂
		int output(int M,int N){return body[M][N];} 
		void output();
};
matrix matrix::multi(matrix x,int mod)//矩阵乘法 
{
	if(n!=x.m) 
	{
		cerr<<"No Way\n";//矩阵AB相乘的条件是A的列数等于B的行数
		exit(-1);
	}
	matrix ans(this->m,x.n);
	for(int i=0;i<m;i++)
		for(int j=0;j<x.n;j++)
			for(int k=0;k<n;k++)
				ans.body[i][j]=(ans.body[i][j]+body[i][k]*x.body[k][j])%mod;
	return ans;
}
matrix matrix::QuickPower(ull index,int mod)//矩阵快速幂 
{
	if(m!=n) 
	{
		cerr<<"No Way\n";//不是方阵 
		exit(-1);
	}
	matrix ans(m,n);
	for(int i=0;i<m;i++) ans.body[i][i]=1;//单位矩阵 
	while(index)
	{
		if(index&1) ans=ans.multi(*this,mod);
		*this=multi(*this,mod);
		index>>=1;
	}
	return ans;
}
void matrix::output()
{
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<body[i][j]<<' ';
		}	
		cout<<endl;	
	}	
} 
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	matrix my(2,2);
	ull n;
	while(cin>>n&&n!=-1)
	{
		my.assign(0,0,1);my.assign(0,1,1);
		my.assign(1,0,1);my.assign(1,1,0);
		my=my.QuickPower(n,10000);
		cout<<my.output(0,1)<<endl;
	}
}

 

用vector写方便好多啊,但效率比上面的低诶,AC代码:

//CSDN博客:https://blog.csdn.net/qq_40889820
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<map>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define random(a,b) (rand()%(b-a+1)+a)
#define ull unsigned long long
#define e 2.71828182
#define Pi 3.141592654
using namespace std;
typedef vector<ull> vec;
typedef vector< vec > matrix;
matrix multi(matrix& a,matrix& b,int mod)
{
	matrix ans(a.size(),vec(b[0].size()));
	for(int i=0;i<a.size();i++)
		for(int j=0;j<b[0].size();j++)
			for(int k=0;k<a[0].size();k++)
				ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%mod; 
	return ans;		
}
matrix QuickPower(matrix a,ull index,int mod)
{
	matrix ans(a.size(),vec(a.size()));
	for(int i=0;i<a.size();i++) ans[i][i]=1;
	while(index)
	{
		if(index&1) ans=multi(a,ans,mod);
		a=multi(a,a,mod);
		index>>=1;
	}
	return ans;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	matrix my(2,vec(2));
	ull N;
	while(cin>>N&&N!=-1)
	{
		my[0][0]=1;my[0][1]=1;
		my[1][0]=1;my[1][1]=0;
		my=QuickPower(my,N,10000);
		cout<<my[0][1]<<endl;
	}
}

提交结果,第一条是使用了vector的,第二题是没有用vector的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值