zoukankan      html  css  js  c++  java
  • hdu3117

    博客图片

    题目链接

    hdu3117

    题目概述

            计算菲波那切数列,如果这个这个数的值不超过8位数,那么输出这个数,否则输出这个数的高42位和低4位,中间以...分隔,输入以EOF结束.

            首先通过打表计算可以当(n < 40)时,这个数列的项是小于8位数的整数.低4位的计算可以通过计算时对10000取模得到,但是因为菲波那切数列的递推式与前面两项相关,直接用递推式计算一个是可能会超时,因为(0 leq n leq 10^8),使用迭代计算时间复杂度为(O(n)),提交上去果然TLE.可以把递推关系转为矩阵表示的:

    [egin{aligned} egin{bmatrix} f(n) & f(n-1) \ 0 & 0 end{bmatrix} = egin{bmatrix} f(n-1) & f(n-2) \ 0 & 0 end{bmatrix} cdot egin{bmatrix} 1 & 1 \ 1 & 0 end{bmatrix} end{aligned} ]

    利用这种方式不断展开,可以得到

    [egin{aligned} egin{bmatrix} f(n) & f(n-1) \ 0 & 0 end{bmatrix} = egin{bmatrix} f(1) & f(0) \ 0 & 0 end{bmatrix} cdot egin{bmatrix} 1 & 1 \ 1 & 0 end{bmatrix}^{n-1} end{aligned} ]

    定义了矩阵的乘法之后,矩阵的幂可以使用矩阵快速幂取模来计算.可以在(O(log(n)))的时间内计算出(f(n)\%10000).

            高4位的计算要用到对数的性质,首先根据菲波那切数列数列的通项公式:

    [f(n) = frac{1}{sqrt5}left((frac{1+sqrt 5}{2})^n-(frac{1-sqrt 5}{2})^n ight) ]

    在渐进意义下((n o infty))(frac{1-sqrt 5}{2} < -1),从而((frac{1-sqrt 5}{2})^n) o 0)可以忽略不计.所以:

    [x = log(frac{1}{sqrt5}(frac{1+sqrt 5}{2})^n)=log(frac{1}{sqrt5})+n*log(frac{1+lsqrt5}{2}) ]

    然后去掉(x)向下取整部分,在将这个数作为10的指数,得到一个介于(1到10)之间的整数,然后不断乘以10,就可以得到对应的高位的数字了.

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 100;
    ll F[N];
    const int M = 2;
    const int MOD = 10000;
    struct Matrix{
        ll m[M][M];
        Matrix(){
            memset(m, 0, sizeof(m));
        }
    };
    void solve(){
        F[1] = F[2] = 1;
        for(int i = 3; i < N; i++){
            F[i] = F[i - 1] + F[i - 2];
        }
    }
    // 矩阵乘法
    Matrix mul (const Matrix& a , const Matrix& b){
        Matrix ans;
        for (int i = 0; i < M; ++i){
            for(int j = 0; j < M; ++j){
                for (int k = 0; k < M; ++k){
                    ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD;
                }
            }
        }
        return ans;
    }
    
    // 矩阵快速幂取模
    Matrix fast_exp_mod(Matrix a, int n){
        Matrix ans;
        for(int i = 0; i < M; i++){
            ans.m[i][i] = 1;
        }
        while( n > 0){
            if( n & 1 ){
                ans = mul(ans,a);
            }
            n >>= 1;
            a = mul( a, a );
        }
        return ans;
    }
    
    const double s = 1.0*(1 + sqrt(5.0))/2;
    
    void solve(int n){
        Matrix base;
        base.m[0][0] = 1;
        Matrix a;
        a.m[0][0] = a.m[0][1] = a.m[1][0] = 1;
        Matrix ans = fast_exp_mod(a, n-1);
        ans = mul(base, ans);
        double b = -0.5 * (log(5) / log(10)) + n*log(s) / log(10);
        b -= floor(b);
        double x = pow(10.0, b);
        while( x < 1000){
            x *= 10;
        }
        printf("%lld...%04lld
    ", (ll)x, ans.m[0][0]);
    }
    
    int main(int argc, const char** argv) {
        solve();
        int n= 0;
        while(~scanf("%d", &n)){
            if( n < 40){
                printf("%lld
    ", F[n]);
            }else{
                solve(n);
            }
        }
        return 0;
    }
    

    其它

  • 相关阅读:
    编程实现折半法查找
    浅谈C++多态性
    纯虚函数的使用汇总
    虚函数如何实现多态 ?
    重载(overload),覆盖(override),隐藏(hide)的区别
    Qt入门之常用Qt标准对话框之QMessageBox
    Qt5学习笔记(5)——列表框QListWidget类
    python 文件的方法
    python---while循环
    python ---strip()方法,split()方法,删除字符串开头或结尾,字符串分隔
  • 原文地址:https://www.cnblogs.com/2018slgys/p/13326299.html
Copyright © 2011-2022 走看看