木块砌墙

用 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];
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值