用矩阵运算 + 快速幂处理斐波那契数列问题

定义斐波那契数列问题:

定义 a0=1a0=1, a1=1a1=1, an=an−1+an−2an=an−1+an−2,求 anan 是多少。
为了避免考虑整数溢出问题,我们求 an%pan%p 的值,p=109+7p=109+7。

快速幂算法的模板可以参考这里。
可以先利用矩阵运算的性质将通项公式变成幂次形式,然后用平方倍增(快速幂)的方法求解第 nn 项。

首先我们定义向量
Xn=[an−1],边界:X1=[a1a0]
Xn=[an−1],边界:X1=[a1a0]
然后我们可以找出矩阵:
A=[1110]
A=[1110]
则有:
Xn=Xn−1×A
Xn=Xn−1×A
所以:

Xn=X1×An−1
Xn=X1×An−1
由于矩阵具有结合律,所以我们可以先求出 An−1%PAn−1%P,然后再用 X1X1 左乘,即可求出 XnXn,向量 XnXn 的第一个元素就是 anan。

时间复杂度分析:快速幂的时间复杂度是 O(logn)O(logn),所以算法5的时间复杂度也是 O(logn)O(logn)。

C++代码

#include 
#include 
#include 
#include 
#include 

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 result(long long n)
{
     
    int x[2] = {
     1, 1};

    int a[2][2] = {
     {
     1, 1}, {
     1, 0}};

    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 << result(n) << endl;

    return 0;
}




你可能感兴趣的:(算法,算法)