思路:
1.我们用r
表示红色,用b
表示蓝色,对于一串长为s
的珠子,它的末尾情况一共会有三种:(1)***b
(2)***br
(3)***brr
(其中第三种包括了b
在离末尾更远的地方),我们设这三个情况的种数分别为a
,b
,c
;
2.此时这串珠子在情况(1)只能继续加红色珠子,得到长度为s+1
的情况(2)的珠子;原珠子在情况(2)也只能继续加红色珠子,得到长度为s+1
的情况(3)的珠子;原珠子在情况三则可以加红珠子和蓝珠子,分别得到长度为s+1
的情况(3)和情况(1)的珠子;
3.因此对于情况为(1)(2)(3)、种数分别为a、b、c
、长度为s
的串,递推到长度为s+1
之后,这串珠子三种情况的长度分别为c、a、b+c
,由此我们可以得到递推矩阵
[
0
0
1
1
0
0
0
1
1
]
∗
[
a
b
c
]
=
[
c
a
b
+
c
]
\left[ \begin{matrix} 0 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 1 \end{matrix} \right]* \left[ \begin{matrix} a \\ b \\ c \end{matrix} \right]= \left[ \begin{matrix} c \\ a \\ b+c \end{matrix} \right]
⎣⎡010001101⎦⎤∗⎣⎡abc⎦⎤=⎣⎡cab+c⎦⎤
4.最后利用矩阵快速幂算一下递推矩阵的n-2
次幂,就可以直接从原始矩阵递推到长度为n
的珠子对应的
3
∗
1
3*1
3∗1矩阵啦,最后将三种情况加起来就可以了;
(PS:如果这题一直超时,大家不妨换成g++
编译器提交一发)
代码:
#include<iostream>
#include<vector>
using namespace std;
template <class T> inline void read(T &res){
char c;do{c=getchar();}while(c<'0'||c>'9');
res=c-'0';while(c=getchar(),c>='0'&&c<='9') res=res*10+(c-'0');
}
inline void out(int x){if(x>9) out(x/10); putchar(x%10+'0');}
typedef long long LL;
typedef vector<int> vec;
typedef vector<vec> mat;
const int M=1e9+7;
mat mul(mat &A,mat & B){
mat C(3,vec(3));
for(int i=0;i<3;i++)
for(int k=0;k<3;k++)
for(int j=0;j<3;j++)
C[i][j]=(C[i][j]+1ll*A[i][k]*B[k][j]%M)%M;
return C;
}
mat Pow(mat A,LL n){
mat B(3,vec(3));
for(int i=0;i<3;i++) B[i][i]=1;
while(n>0){
if(n&1) B=mul(B,A);
A=mul(A,A);
n>>=1;
}
return B;
}
LL n;
mat A={{0,0,1},{1,0,0},{0,1,1}};
void solve(){
read(n);
mat B=Pow(A,n-2);
int ans=0;
for(int i=0;i<3;i++) for(int j=0;j<3;j++) ans=(ans+B[i][j])%M;
out(ans); putchar('\n');
}
int main(){
int t; read(t);
while(t--) solve();
return 0;
}