题目描述
已知一个数列 a,它满足:
求 a 数列的第 n 项对 取余的值。
输入格式
第一行一个整数 T,表示询问个数。
以下 T 行,每行一个正整数 n。
输出格式
每行输出一个非负整数表示答案。
输入输出样例
输入 #1
3
6
8
10
输出 #1
4
9
19
说明/提示
- 对于 30% 的数据 ;
- 对于 60% 的数据 ;
- 对于 100% 的数据 。
题目分析
题意很简单,求数列第n项的内容。但是注意n的范围, 。即便是的递推,依然会超时。
从矩阵的角度观察递推式:f[n]=f[n-1]+f[n-3]
设矩阵A为:$ \begin{bmatrix}
a_{n-3} & a_{n-2} & a_{n-1}
\end{bmatrix} $。
那么意味着
那么加速矩阵B即可推出为
可发现,每乘一次矩阵B,即可向后推一项。那么求第n项就变成了求 。我们可以采用矩阵快速幂的方式在的时间复杂度内求解。
代码实现
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=5;
const int M=1e9+7;
struct node{
ll a[N][N]={0};
int row,col;
};
node I;//单位矩阵
node matrixMins(node a,node b){//矩阵乘法
node c;//答案矩阵
c.row=a.row;
c.col=b.col;
int n=c.row,p=c.col,m=a.col;
//计算矩阵乘法
for(int i=1;i<=n;i++){
for(int j=1;j<=p;j++){
for(int k=1;k<=m;k++){
c.a[i][j]+=a.a[i][k]*b.a[k][j]%M;
c.a[i][j]%=M;
}
}
}
return c;
}
node matrixPow(node a,ll k){//矩阵的幂次方
if(k==0){// 0次方
return I;//矩阵的0次方是单位矩阵
}
node t=matrixPow(a,k/2);//求 a^{n/2} 次方
if(k&1){//判断k是否是奇数
return matrixMins(matrixMins(t,t),a);
}else{//k是偶数
return matrixMins(t,t);
}
}
int main(){
int t;
node a;
ll n;
cin>>t;
//处理 加速递推矩阵
a=node{
{
{0},
{0,0,0,1},
{0,1,0,0},
{0,0,1,1}
},3,3
};
//处理 单位矩阵
I=node{
{
{0},
{0,1,0,0},
{0,0,1,0},
{0,0,0,1}
},3,3
};
//处理数列初始值 [1 1 2 3]
node tt={
{
{0},
{0,0,1,1}
},1,3
};
while(t--){
cin>>n;
node tmp=matrixPow(a,n);//计算A^n
node ans=matrixMins(tt,tmp);
cout<<ans.a[1][1]<<endl;
}
return 0;
}