题目描述:
在斐波那契数列中,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;
}