斐波那契数列O(logn)的求解方法

前言

是的,没错,斐波那契数列除了递推、递归算法之外,还有更加高效的求解方法,那就是矩阵运算+快速幂。

思路:
可以先利用矩阵运算的性质将通项公式变成幂次形式,然后用平方倍增(快速幂)的方法求解第 n 项。

首先我们定义向量
Xn=[an an−1],边界:X1=[a1 a0]
然后我们可以找出矩阵:
A = [ 1 1 1 0 ] A=\left[ \begin{matrix} 1 & 1 \\ 1& 0 \end{matrix} \right] A=[1110]
则有:
Xn=Xn−1×A
所以:
Xn=X1×An−1
由于矩阵具有结合律,所以我们可以先求出 An−1%P,然后再用 X1左乘,即可求出 Xn,向量 Xn 的第一个元素就是 an

具体实现:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <ctime>

using namespace std;

const int MOD = 1000000007;

void mul(int a[][2], int b[][2], int c[][2])
{
    int temp[][2] = {{0, 0}, {0, 0}};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            for (int k = 0; k < 2; k ++ )
            {
                long long x = temp[i][j] + (long long)a[i][k] * b[k][j];
                temp[i][j] = x % MOD;
            }
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            c[i][j] = temp[i][j];
}


int f_final(long long n)
{
    int x[2] = {1, 1};

    int res[][2] = {{1, 0}, {0, 1}};
    int t[][2] = {{1, 1}, {1, 0}};
    long long k = n - 1;
    while (k)
    {
        if (k&1) mul(res, t, res);
        mul(t, t, t);
        k >>= 1;
    }

    int c[2] = {0, 0};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
        {
            long long r = c[i] + (long long)x[j] * res[j][i];
            c[i] = r % MOD;
        }

    return c[0];
}


int main()
{
    long long n ;

    cin >> n;
    cout << f_final(n) << endl;

    return 0;
}

说明:
参考y总的总结
链接:https://www.acwing.com/blog/content/25/
来源:AcWing

你可能感兴趣的:(方法总结,算法,数据结构)