矩阵乘法:
[F(n+1)]=[1 1][F(n) ]
[F(n) ]=[1 0][F(n-1)]
结果
F(n+1)=F(n)+F(n-1)
F(n)=F(n)
设[ 1 1]
[ 1 0]为A
则: F = A^n 所以Fib(n) = F[0][0]
之前不知道斐波那契数的矩阵求法,了解了以后觉得矩阵的时间复杂度和迭代应该一样啊。其实,矩阵连乘的真正威力在于求高效幂的算法。
乘法方法有比加法更好的性质,用加法只能利用前两个的值,而乘法却不同,因为乘法有结合律,可以大幅度下降算法的耗时。
因为方阵的乘法有结合律,所以A(2)^n=A(2)^(n/2)*A(2)^(n/2),不妨设n是偶数所以求A(n)就可以化成求A(n/2)并作一次乘法。
所以递归方程是:T(n)=T(n/2)+O(1),它的解是O(logn)。
代码没有优化,内存占用大概在 260K 左右。
不死兔子
Time Limit:1000MS Memory Limit:65536K
Total Submit:278 Accepted:31
Description
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔都不死,那么一年以后可以繁殖多少对兔子?
我们不妨拿新出生的一对小兔子分析一下:
第一个月小兔子没有繁殖能力,所以还是一对;
两个月后,生下一对小兔,共有两对;
三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对;
------
依次类推可以列出下表:
表中数字0,1,1,2,3,5,8---构成了一个数列,这个数列你是不是很熟悉呢?
对于给定的非负整数 n ,请编写程序计算出经过n个月后的兔子对数,因为结果可能很大,请输出MOD (2011403)后的结果。
Input
第1行是一个整数t,
第2~t+1行,每行一个非负整数n(0≤n≤1 000 000 000)
Output
对于每个n,请输出n个月后兔子的对数Mod(2011403)后的结果,每个结果占一行。
Sample Input
3
1
3
5
Sample Output
1
3
8
Hint
为解答此题,你可能需要更高效的算法
代码:
#define M 2011403
using namespace std;
typedef __int64 LL;
class matrix{
public:
int mat[2][2];
matrix identity_matrix(){//单位矩阵
matrix ret;
ret.mat[0][0] = 1;
ret.mat[1][1] = 1;
ret.mat[0][1] = 0;
ret.mat[1][0] = 0;
return ret;
}
matrix operator * (matrix m){
matrix ret;
int i,j,k;
for(i = 0; i < 2; ++ i){
for(j = 0; j < 2; ++ j){
LL c = 0;
for(k = 0; k < 2; ++ k)
c = (c + (LL)mat[i][k] * m.mat[k][j] % M) % M;
ret.mat[i][j] = c;
}
}
return ret;
}
matrix operator ^ (int k){//高效幂
if(k == 0) return identity_matrix();
matrix ret = * this, a = ret;
--k;
while(k){
if(k & 1) ret = ret * a;
a = a * a;
k >>= 1;
}
return ret;
}
};
int Fib(int n){
if(n <= 1)
return 1 % M;
matrix F;
F.mat[0][0] = 1;
F.mat[0][1] = 1;
F.mat[1][0] = 1;
F.mat[1][1] = 0;
F = F ^ (n - 1);
return (F.mat[0][0] + F.mat[0][1] ) % M;
}
int main() {
int n,N;
cin>>N;
while (N--){
cin>>n;
cout<<Fib(n)<<endl;
}
return 0;
}
另:刚开始做的时候用的是循环节,虽然AC可是内存占用巨大,差一点就超了,时间消耗也够呛。
代码:
//此题是利用循环节做的
#include <iostream>
#define MOD 2011403
#define MAX 10000000
using namespace std;
int fib[MAX];
int main()
{
int T,n,i;
cin>>T;
while(T--)
{
cin>>n;
fib[0]=fib[1]=1;
for(i=2;i<MAX;i++)
{
fib[i]=(fib[i-1]+fib[i-2])%MOD;
if(fib[i]==1 && fib[i-1]==1)
break;
}
n%=(i-1);
if(n==0)
cout<<fib[i-1]<<endl;
else
cout<<fib[n]<<endl;
}
return 0;
}