题目大意:用2x1的方块铺满4xN的格子,有多少种不同的铺法。
这个题目是一个计数问题。把格子看成4列N行,假设现在要铺第n+1行(即第n行已铺满),则第n+1行有如下情况:
由图不难得出:
an+1=an+bxn+byn+cn+en
bxn+1=an+byn
byn+1=an+bxn
cn+1=an+dn
dn+1=cn
en+1=an
若令bn=bxn+byn,则可以进一步简化上述递推式:
an+1=an+bn+cn+en
bn+1=2an+bn
cn+1=an+dn
dn+1=cn
en+1=an
令
F=⎡⎣⎢⎢⎢⎢⎢⎢1210111000100100010010000⎤⎦⎥⎥⎥⎥⎥⎥An=⎡⎣⎢⎢⎢⎢⎢⎢anbncndnen⎤⎦⎥⎥⎥⎥⎥⎥
则An+1=FAn
根据定义,显然
A1=⎡⎣⎢⎢⎢⎢⎢⎢12101⎤⎦⎥⎥⎥⎥⎥⎥
通过矩阵的快速幂算法即可求出An,得到答案an。
#include<iostream>
#include<cstring>
using namespace std;
struct FFF {
int matrix[5][5];
FFF operator*(const FFF& nec) {
FFF ret;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++) {
ret.matrix[i][j] = 0;
for (int k = 0; k < 5; k++)
ret.matrix[i][j] += matrix[i][k] * nec.matrix[k][j];
}
return ret;
}
FFF operator%(int mod) {
FFF ret;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
ret.matrix[i][j] = matrix[i][j] % mod;
return ret;
}
}F = { {
{1,1,1,0,1},
{2,1,0,0,0},
{1,0,0,1,0},
{0,0,1,0,0},
{1,0,0,0,0}
}
};
int A[5] = { 1,2,1,0,1 };
int main()
{
int n, m;
cin >> n >> m;
while (n)
{
FFF M = F, E;
memset(E.matrix, 0, sizeof(E.matrix));
for (int i = 0; i < 5; i++)
E.matrix[i][i] = 1;
for (int i = n - 1; i != 0; i >>= 1)
{
if (i & 1) E = M*E%m;
M = M*M%m;
}
int ans = 0;
for (int i = 0; i < 5; i++)
ans += E.matrix[0][i] * A[i];
cout << ans%m << endl;
cin >> n >> m;
}
return 0;
}