用 1×1×1, 1×2×1以及2×1×1的三种木块(横绿竖蓝,且绿蓝长度均为2),
搭建高长宽分别为K × 2^N × 1的墙,不能翻转、旋转(其中,0<=N<=1024,1<=K<=4)
有多少种方案,输出结果
对1000000007取模。
举个例子如给定高度和长度:N=1 K=2,则答案是7,即有7种搭法。
#ifdef WIN32
#define ll __int64
#else
#define ll long long
#endif
#define MOD 1000000007
void calCase(int cases[6][32][32], int cols, int curCol, int lastLineState,
int curLineState) {
if (curCol >= cols) {
++cases[cols][lastLineState][curLineState];
return;
}
/* 当上行的curCol位置空时填入(1*1); 或者当非空时 ,不填; 2种情况都不影响当前行对应位*/
calCase(cases, cols, curCol + 1, lastLineState, curLineState);
if (((lastLineState >> curCol) & 1) == 0) { //上一行curCol位为空
calCase(cases, cols, curCol + 1, lastLineState, //填入2*1
curLineState | (1 << curCol));
if (curCol + 1 < cols && (((lastLineState >> (curCol + 1)) & 1) == 0)) {//连续2格为空, 填入1*2
calCase(cases, cols, curCol + 2, lastLineState, curLineState);
}
}
}
int mul(int a, int b) {
return a * b % MOD;
}
void multiply(int n, int a[][32], int b[][32]) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = b[i][j] = 0; k < n; ++k) { //枚举状态
if ((b[i][j] += mul(a[i][k], a[k][j])) >= MOD) {
b[i][j] -= MOD;
}
}
}
}
}
/*2^n行, k列*/
int calculate(int n, int k) {
/*cases[col][lastLineState][curLineState]
:共col列下, 上一行状态为
* lastLineState,将上行填满后, 当前行的状态为curLineState的方法数*/
int cases[6][32][32], mat[2][32][32];
memset(cases, 0, sizeof(cases));
//预处理
for (int i = 1; i <= 5; ++i) {
for (int j = (1 << i) - 1; j >= 0; --j) {
calCase(cases, i, 0, j, 0);
}
}
memcpy(mat[0], cases[k], sizeof(mat[0]));
k = 1 << k;
int i = 0;
for (i = 0; n; n--) {
multiply(k, mat[i], mat[i ^ 1]);
i ^= 1;
}
//首行为空,最后一行(非有效行必须为空),则取mat[i][0][0]
return mat[i][0][0];
}
1222

被折叠的 条评论
为什么被折叠?



