这个题目考察的是快速幂和线性代数,看题解有多种方法,我比较认可的是用3*3矩阵来运算。
当我直接拿到这个题目的时候,第一感觉是Dp
但是比较明显的是在这个题目里面,如果单个dp对应的是一个元素,问题不是dp会重复计算而是计算的总次数过多,状态转移不通畅,这种大数据其实适合的是使用快速幂,思路转移到直接计算,对于这个题前三项都是1,我们可以使用线性代数,把这个题目转化成快速幂问题,即f2 = M*f1(M就是转移矩阵)
每一次转移之后使得矩阵[a1,a2,a3]变成[a2,a3,a4],
求得对应的转移矩阵,最后就能将数列转化成矩阵的幂的问题,用快速幂来求m的n-3次幂,最后再乘以[a1,a2,a3],最后返回ans即可。
线性代数的应用在这个题目里面很有趣,使用不同的数据结构来进行转化运算的逻辑,这是我们可以养成的一个意识。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
struct Matrix
{
ll mat[3][3];
Matrix()
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
mat[i][j]=0;
}
}
}
};
Matrix caculate(Matrix A, Matrix B)
{
Matrix res;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
for(int k = 0; k < 3; k++)
{
res.mat[i][j] = (A.mat[i][k]*B.mat[k][j] + res.mat[i][j])%MOD;
}
}
}
return res;
}
Matrix qpow(Matrix a, ll b)
{
Matrix res;
for(int i = 0; i < 3; i++) res.mat[i][i]=1;
while(b>0)
{
if(b%2==1)
{
res = caculate(res,a);
}
a = caculate(a,a);
b >>= 1;
}
return res;
}
void solve()
{
ll n;
cin >> n;
if(n<3)
{
cout << 1 << endl;
return;
}
Matrix m;
m.mat[0][0]=1;m.mat[0][1]=0;m.mat[0][2]=1;
m.mat[1][0]=1;m.mat[1][1]=0;m.mat[1][2]=0;
m.mat[2][0]=0;m.mat[2][1]=1;m.mat[2][2]=0;
Matrix M_n_minus_3 = qpow(m,n-3);
ll ans = ( M_n_minus_3.mat[0][0] * 1 +
M_n_minus_3.mat[0][1] * 1 +
M_n_minus_3.mat[0][2] * 1) % MOD;
cout << ans << endl;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int T;
cin >> T;
for(int i = 0; i < T; i++) solve();
return 0;
}

京公网安备 11010502036488号