类比斐波那契数列的矩阵快速幂算法即可解决这个问题。
考虑斐波那契数量的相同问题,其核心在于将写成矩阵和向量的递推式:
其中,
,
搞清楚这里是怎么做的,就可以做出本题了。 两个核心问题,是什么?
是多少?
可以发现,矩阵的第一行得到的就是原始递推式,而第二行则是因为右侧向量就含有这个分量(线性相关)。类似的,我们要让本题的向量设置也是能够相邻的,因此设
因此,基于本题的递推
可以写出递推式
因此,就有了
至此,只需要使用矩阵的快速幂即可,这只需要将一般的快速幂中的操作改成矩阵乘法即可.
提供一个模版以及AC代码:
#include <cassert>
#include <cstdint>
#include <iostream>
#include <cstring>
using namespace std;
const int64_t MOD = 1e9 + 7;
template <int N>
struct Matrix {
int64_t mat[N][N] {};
void init_identity() {
memset(mat, 0, sizeof(mat));
for (int i = 0; i < N; i++) mat[i][i] = 1;
}
Matrix operator*(const Matrix& b) const {
Matrix res;
for (int i = 0; i < N; i++) {
for (int k = 0; k < N; k++) {
if (!mat[i][k]) continue;
for (int j = 0; j < N; j++) {
res.mat[i][j] = (res.mat[i][j] + mat[i][k] * b.mat[k][j]) % MOD;
}
}
}
return res;
}
};
template <int N>
Matrix<N> qpow(Matrix<N> a, int64_t b) {
Matrix<N> res;
res.init_identity();
for (; b; b >>= 1, a = a * a) {
if (b & 1) res = res * a;
}
return res;
}
int64_t boficcina(int64_t n) {
assert(n > 0);
if (n <= 3) return 1;
static const Matrix<3> m = {1, 0, 1, 1, 0, 0, 0, 1, 0};
Matrix<3> res = qpow(m, n - 3);
return (res.mat[0][0] + res.mat[0][1] + res.mat[0][2])%MOD;
}
void solve() {
int n;
cin >> n;
cout << boficcina(n) << '\n';
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
}
// 64 位输出请用 printf("%lld")

京公网安备 11010502036488号