题目大意:用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;
}