zoukankan      html  css  js  c++  java
  • 矩阵连乘求超大斐波那契数 ZZULI 1478 不死兔子

     

      矩阵乘法:
      [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

    为解答此题,你可能需要更高效的算法

     代码:

    #include <iostream>
    #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可是内存占用巨大,差一点就超了,时间消耗也够呛。

    代码:

    //zzuli 1478
    //此题是利用循环节做的
    #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;
    }
  • 相关阅读:
    win8 64下启动Apache失败:443端口被占用的解决方法
    JavaScript初学者应注意的七个细节
    再说SQL Server数据库优化
    2010.Net程序员年终随笔
    基于Siverlight 3.0的超炫图表工具Visifire 最后一个免费版本,你还等什么?
    苦修六年 终成正果 幸福之路 从此开始
    Asp.net中服务端控件事件是如何触发的(笔记)
    我的缓存实例—工作记录
    坚持观点:决不为了用Linq而用Linq!!
    ASP.NET 之 常用类、方法的超级总结,并包含动态的EXCEL导入导出功能,奉上类库源码
  • 原文地址:https://www.cnblogs.com/bl4nk/p/2022895.html
Copyright © 2011-2022 走看看