AcWing 205 斐波那契

题目描述:

在斐波那契数列中,Fib0=0,Fib1=1,Fibn=Fibn−1+Fibn−2(n>1)。给定整数n,求Fibnmod10000。

输入格式

输入包含多组测试用例。每个测试用例占一行,包含一个整数n。当输入用例n=-1时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个整数表示结果。每个结果占一行。

数据范围

0≤n≤2∗10^9

输入样例:

0
9
999999999
1000000000
-1

输出样例:

0
34
626
6875

分析:

本题若采用递推,线性的时间复杂度,2*10^9是不能承受的。我们采用矩阵乘法加速递推。

现在设F[n] = [fib(n) fib(n+1)],有F[n-1] = [fib(n-1) fib(n)]。现在假设有一2*2的矩阵p,使得F[n-1] * p = F[n],解方程得p = [0 1]->第一行 [1,1]->第二行。该递推式的初值为F[0] = [0 1],可以推导出F[n] = F[0] * p^n.这里的F[n]被称为状态矩阵,p被称为转移矩阵。

这里求矩阵p的n次幂可以参考快速幂算法。

比如求a^b % p 。

while(b > 0){
    if(b & 1){
         ans = ans * a % p;
     }
     a = a * a % p;
     b >>= 1;
 }

我们这里的a是2*2的矩阵,b是一个整数,所以只用将所有的乘法改为矩阵乘法即可。所以采用矩阵乘法求得斐波那契数的时间复杂度为O(logn)。

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int mod = 10000;
typedef long long ll;
int n;
void mul(int f[2],int a[2][2]){//矩阵乘法 
	int c[2];
	memset(c,0,sizeof(c));
	for(int i = 0;i < 2;i++)
		for(int j = 0;j < 2;j++)
			c[i] = (c[i] + (ll)f[j] * a[j][i]) % mod;
	memcpy(f,c,sizeof(c));
}
void mulself(int a[2][2]){//矩阵平方
	int c[2][2];
	memset(c,0,sizeof(c));
	for(int i = 0;i < 2;i++)
		for(int j = 0;j < 2;j++)
			for(int k = 0;k < 2;k++)
				c[i][j] = (c[i][j] + (ll)a[i][k] * a[k][j]) % mod;
	memcpy(a,c,sizeof(c));
}
int main(){
	while(cin>>n && n != -1){
		int f[2] = {0,1};
		int a[2][2] = {{0,1},{1,1}};
		for(; n;n >>= 1){
			if(n & 1)	mul(f,a);
			mulself(a);
		}
		cout<<f[0]<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30277239/article/details/87901787