題目大意:用n-1個1X2的格子和2個1X1的格子鋪成nX2的格子,要求2個1X1的格子不能相鄰。(n <= 1e9, 結果取模1e9+7)
題解:
如果沒有沒有兩個1X1的格子,則答案就是斐波拉契數列,當加入了兩個1X1的格子後,我們需要在遞推的時候考慮放1X1的格子的情況。假設答案爲 g[n] ,斐波拉契數列爲 f[n], 斐波拉契數列的和爲S[n].
所以當g[n] = (g[n-1] + g[n-2])(兩個1X1都不在新加入的格子) + 2*S[n-3](當有1個1X1在新加入的格子即第n個1X2,另一個可能在1...n-2,由於連個1X1之間的放置方法是固定的,所以總的方法數位f[1] + f[2] + f[3] + ... + f[n-3]),
又因爲S[n-3] = f[n-1] - 1 所以
所以可以用矩陣快速冪,係數矩陣爲 初始值
代碼:
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
struct Matrix{
int a[5][5];
Matrix operator *(const Matrix &b) const
{
Matrix res;
memset(res.a, 0 ,sizeof(res.a));
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
for(int k = 0; k < 5; k++)
res.a[i][j] = (res.a[i][j] + (1LL* a[i][k] * b.a[k][j])%mod)%mod;
return res;
}
void put()
{
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
cout << a[i][j] << " ";
cout << endl;
}
}
};
Matrix mfpow(Matrix x, int n)
{
if(n <= 0) return x;
Matrix res;
memset(res.a,0,sizeof(res.a));
for(int i = 0; i < 5; i++) res.a[i][i] = 1;
while(n)
{
//x.put();
//cout << n <<"***"<< endl;
if(n&1) res = res * x;
x = x * x;
n >>= 1;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
Matrix st;
int b[5][5] = {{1,1,2,2,1},{1,0,0,0,0},{0,0,1,1,0},{0,0,1,0,0},{0,0,0,0,1}};
for(int i = 0; i < 5; i++) for(int j = 0; j < 5; j++) st.a[i][j] = b[i][j];
Matrix ed = mfpow(st,n-1);
int res = (0LL + ed.a[1][2] + ed.a[1][3] - ed.a[1][4]*2 + 2*mod)%mod;
printf("%d\n",res);
}
return 0;
}