一、題目
二、解法
設爲大小爲的矩陣填充的方案數,首先考慮不放特殊格子(),那麼可以從和轉移而來。考慮放特殊格子的情況,無論是放上面還是放下面,前面的格子的放法總是唯一的(和間隔的奇偶性有關),而且一定是要空兩格的,設爲大小爲的矩陣只用的小矩陣填充的方案數,那麼還可以從轉移過來,綜上我們可以寫出轉移方程:
這裏對轉移方程進行了簡寫,首先從的角度可得是一個斐波那契數列,要證明一個結論:,可以用歸納法,當時成立,假設時成立,那麼,即,故時也成立,證畢。
顯然上面的可以用矩陣加速,如果不會構造矩陣的童鞋可以看下面的圖:
時間複雜度,貼個代碼。
#include <cstdio>
#include <cstring>
#define int long long
const int MOD = 1e9+7;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n;
struct Matrix
{
int n,m,a[8][8];
Matrix() {n=m=0;memset(a,0,sizeof a);}
Matrix operator * (const Matrix &b) const
{
Matrix r;
r.n=n;r.m=b.m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=b.m;k++)
{
r.a[i][k]=(r.a[i][k]+a[i][j]*b.a[j][k])%MOD;
r.a[i][k]=(r.a[i][k]+MOD)%MOD;
}
return r;
}
}A,F;
Matrix qkpow(Matrix a,int b)
{
Matrix r;
r.n=r.m=a.n;
for(int i=1;i<=r.n;i++)
r.a[i][i]=1;
while(b>0)
{
if(b&1) r=r*a;
a=a*a;
b>>=1;
}
return r;
}
signed main()
{
T=read();
while(T--)
{
n=read();
if(n<=2)
{
puts("0");
continue;
}
A.n=A.m=F.n=5;F.m=1;
A.a[1][1]=A.a[1][2]=A.a[2][1]=
A.a[3][3]=A.a[3][4]=A.a[4][3]=A.a[5][5]=1;
A.a[1][3]=2;A.a[1][5]=-2;
F.a[3][1]=2;F.a[4][1]=F.a[5][1]=1;
printf("%lld\n",(qkpow(A,n-2)*F).a[1][1]);
}
}