思路:

题目的主要信息:

  • 斐波那契数列,其中

方法一:暴力解法(超时)
具体做法:
使用动态规划求斐波那契数列前n项的值,然后三个循环按照公式相加。

class Solution {
public:
    int mod = 1e9 + 7;
    int getSum(int n) {
        vector<int> dp(n + 1, 0); //动态规划求前n个斐波那契数列
        dp[1] = 1;
        for(int i = 2; i <= n; i++) 
            dp[i] = (dp[i - 2] + dp[i - 1]) % mod; //公式相加
        int res = 0;
        for(int i = 1; i <= n; i++) //三层遍历,按照公式
            for(int j = 1; j <= i; j++)
                for(int k = 1; k <= j; k++)
                    res = (res + dp[k]) % mod;
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,求所有的斐波那契数列为,最后的公式三层循环
  • 空间复杂度:,辅助数组dp记录前项斐波那契数列

方法二:矩阵快速幂
具体做法:
上述做法加得太过于复杂,毕竟这是相当于一个数列相加,我们用数列求和的方式对其化简一下:
图片说明

得到如上图所示的递推公式以后,我们可以将其换成矩阵写法:
图片说明

于是我们只需要得到中间那个数字矩阵的次方,然后再与后面一个矩阵相乘,第一个元素即是我们要求的,其中.

为了快速求中间那个矩阵的的次方,我们可以采用矩阵快速幂。参考数字的快速幂 ,矩阵也有类似的算法:
图片说明
可以使用类似二分的方法来计算矩阵的幂,这样我们只需要计算即可。

class Solution {
public:
    int mod = 1e9 + 7;
    vector<vector<long>> base = { //由刚刚推算出的基础矩阵
        {1, 1, 1, 1, 1},
        {0, 1, 1, 1, 1},
        {0, 0, 1, 1, 1},
        {0, 0, 0, 1, 1},
        {0, 0, 0, 1, 0}
    };
    vector<vector<long>> Mul(vector<vector<long>>& x, vector<vector<long>>& y){ //x矩阵乘上y矩阵
        int n = y[0].size(); //查看第二维是1还是5
        vector<vector<long>> res(5, vector<long>(n, 0));
        for(int i = 0; i < 5; i++){ //遍历相乘相加
            for(int j = 0; j < n; j++){
                for(int k = 0; k < 5; k++){
                    res[i][j] = (res[i][j] + x[i][k] * y[k][j]) % mod; 
                }
            }
        }
        return res;
    }
    vector<vector<long>> Pow(vector<vector<long>>& x, int k){ //矩阵快速幂
        vector<vector<long>> res(5, vector<long>(5, 0));
        for(int i = 0; i < 5; i++)
            res[i][i] = 1; //初始化为单位矩阵
        while(k){
            if(k & 1) 
                res = Mul(res, base);
            k = k >> 1;
            base = Mul(base, base);
        }
        return res;
    }
    int getSum(int n) {
        if(n == 1) //优先判断1和2
            return 1;
        if(n == 2)
            return 4;
        vector<vector<long>> a = base;
        vector<vector<long>> b = {{4},{3},{2},{1},{1}}; 
        vector<vector<long>> c = Pow(a, n - 2); //基础矩阵的n-2次方
        return (int)Mul(c, b)[0][0]; //二者相乘
    }
};

复杂度分析:

  • 时间复杂度:,矩阵快速幂一共调用次乘法运算,乘法运算为复杂度为,故总时间复杂度为
  • 空间复杂度:,所有辅助矩阵要么是要么就是,属于常数空间