问题分析

对于给定的递推数列 ),其本质是一个高阶(三阶)常系数线性齐次递推关系

  1. 时间复杂度瓶颈:查询数量 ,项数 。若采用传统的动态规划进行 的线性递推,单次查询最高将达到 次运算,总运算量达 ,这会引发严重的超时。
  2. 空间复杂度限制:由于 极大,若尝试采用空间换时间(预处理并存储所有结果),将需要约 的连续内存(假设使用 32 位整型),这必然导致内存超限。
  3. 数据溢出风险:由于数列呈指数级变大,且要求对 取模,在任何涉及加法或乘法的算术操作中,不仅最终结果需要取模,中间运算过程也会迅速突破 32 位整型的上限,必须在所有子操作中严格应用模运算律。

算法:矩阵快速幂

针对超大项数的常系数线性递推问题,矩阵快速幂是唯一的工业级标准解法。它将线性的递推过程转化为矩阵的幂运算,从而利用“快速幂”算法的倍增思想,将线性时间复杂度降维至对数时间复杂度。

状态空间的矩阵化

设状态列向量 ,我们需要构造一个状态转移矩阵 ,使得

根据递推公式:

由此抽离出 的转移矩阵

状态转移通项

已知基础状态为 时的值,提取基础列向量

根据矩阵的结合律,对于任意 ,可推导出状态列向量通式:

目标值 即为结果列向量 的第一行元素。

复杂度分析

  • 时间复杂度。其中 为矩阵维度(本题 )。两个 矩阵相乘耗时 ,指数递减需 步。完全满足 1 秒执行完毕的性能要求。
  • 空间复杂度。整个计算生命周期内仅需维护常量个 的矩阵,空间开销可忽略不计。

代码实现

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

static constexpr int MOD = 1e9 + 7;

struct Matrix {
    array<array<ll, 3>, 3> data{};

    // 单位矩阵
    static Matrix identity() {
        Matrix res;
        for (int i = 0; i < 3; i++)
            res.data[i][i] = 1;
        return res;
    }

    Matrix operator*(const Matrix& other) const {
        Matrix res;
        for (int i = 0; i < 3; i++) {
            for (int k = 0; k < 3; k++) {
                if (data[i][k] == 0)
                    continue;
                for (int j = 0; j < 3; j++) {
                    res.data[i][j] = (res.data[i][j] + data[i][k] * other.data[k][j]) % MOD;
                }
            }
        }
        return res;
    }
};

template <typename T>
T power(T base, ll exp) {
    T res = T::identity();
    while (exp > 0) {
        if (exp & 1)
            res = res * base;
        base = base * base;
        exp >>= 1;
    }
    return res;
}

void solve() {
    int n;
    cin >> n;

    if (n <= 3) {
        cout << 1 << "\n";
        return;
    }

    Matrix T;
    T.data = {{
            {1, 0, 1},
            {1, 0, 0},
            {0, 1, 0}
        }
    };

    auto res = power(T, n - 3);

    ll ans = 0;
    for (int j = 0; j < 3; j++) {
        ans = (ans + res.data[0][j]) % MOD;
    }

    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while (T--) {
        solve();
    }

    return 0;
}