hdu3117 Fibonacci Numbers(数论+矩阵快速幂)

题目链接: 3117 ( Fibonacci Numbers )

位数小于 \(8\) 的可以打表直接输出。

对于位数大于 \(8\) 的,直接用大数求 \(Fibonacci\) 的第 \(n\) 项会 \(TLE\) ,因此需分别求解前 \(4\) 位和后 \(4\) 位。

后 \(4\) 位直接矩阵快速幂取模即可,参见 poj3070 Fibonacci(矩阵快速幂取模) ,或者直接打表后四位找循环节更简单,网上有博主表示第 \(1500\) 项开始出现循环。

至于前四位,需要用到 \(Fibonacci\) 数列的通项公式:

\[\begin{align} Fib_n&=\frac{1}{\sqrt{5}}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n] \\ &\approx \frac{1}{\sqrt{5}}(\frac{1+\sqrt5}{2})^n(n\ge0) \\ \epsilon &=\vert\frac{1}{\sqrt{5}}(\frac{1-\sqrt5}{2})^n\vert\le\frac1{\sqrt5}<\frac12 \end{align} \]

因此,\(Fibonacci\) 的第 \(n\) 项即为 \(\frac{1}{\sqrt{5}}(\frac{1+\sqrt5}{2})^n\) 四舍五入。

利用这一公式结合对数运算可直接求出第 \(n\) 个 \(Fibonacci\) 数的前四位。

/**
 * hdu3117 Fibonacci Numbers
 *
 */

#include <iostream>
#include <climits>
#include <vector>
#include <cmath>
#include <iomanip>
using namespace std;

typedef long long LL;

struct Matrix
{
    LL mod;
    vector<vector<LL> > m;
    Matrix(int row, int col, LL mod = LLONG_MAX)
    {
        this->mod = mod;
        m.resize(row, vector<LL>(col));
    }
    Matrix operator * (const Matrix &t) const
    {
        int row = m.size(), col = t.m[0].size(), cnt = m[0].size();
        Matrix res(row, col, mod);
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                for (int k = 0; k < cnt; ++k) {
                    res.m[i][j] += m[i][k]*t.m[k][j]%mod;
                    res.m[i][j] %= mod;
                }
            }
        }
        return res;
    }
};

Matrix fastPow(Matrix a, LL b, LL mod = LLONG_MAX)
{
    int n = a.m.size();
    Matrix t(n, n, mod);
    for (int i = 0; i < n; ++i) t.m[i][i] = 1;
    while (b) {
        if (b&1) t = t*a;
        a = a*a;
        b >>= 1;
    }
    return t;
}

const int mod = 10000;

int main()
{
    // 位数小于等于8则查表直接输出
    vector<long long> f = {0, 1};
    for (int i = 2; f[i-1] < 1e8; ++i) {
        LL t = f[i-1]+f[i-2];
        if (t > 1e8) break;
        f.push_back(t);
    }

    int n;
    Matrix A(2, 2, mod);
    A.m[0][0] = A.m[0][1] = A.m[1][0] = 1;
    while (cin >> n) {
        if (n < f.size()) {
            cout << f[n] << endl;
            continue;
        }

        double res = n*log10((1+sqrt(5))/2) - log10(sqrt(5));
        res = res - (LL) res;
        res = pow(10, res);
        LL ans = res*1000;
        cout << ans << "..."
             << setw(4) << setfill('0')  // 后四位可能有前导0
             << fastPow(A, n, mod).m[0][1] << endl;
    }
    return 0;
}

上一篇:python ----Fibonacci数列


下一篇:pta 6-8 使用函数求Fibonacci数 (15 分)