专栏文章

SP3883 题解

SP3883题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqamzfo
此快照首次捕获于
2025/12/04 01:41
3 个月前
此快照最后确认于
2025/12/04 01:41
3 个月前
查看原文
和其他两篇题解的 dp 思路稍许不同,因为有两维且是状压。
正常来说一维可能是不够的,因为有可能枚举到一列时后面一行用 1×21 \times 2 的骨牌铺导致多了个尾巴,那我们就以后面一行尾巴的状态来进行状压。
设状态 dpi,jdp_{i,j} 表示前 ii 行均填满,第 i+1i + 1 行多出来的尾巴二进制状态是 jj 时的方案数。比如 dp4,5dp_{4,5} 的情形如下:
那么还差一个转移方程。dpi,jdp_{i,j} 能转移到 dpi1,kdp_{i-1,k} 有一个必然条件,那就是 jjkk 的与运算必须是 00。如果不是 00 的话,那么必然存在 jjkk 的某一位都是 11,那么中间一个格子会被占用两次,这显然是不合法的。还有一种情况是转移了之后中间一列的格子无法覆盖。在这种情况下,中间一列空出来的值(转化为二进制数)不可能为 0,3,60,3,63366 都可以用一张 2×12 \times 1 的骨牌覆盖完。当这种情况也合法的话,状态就可以转移了。
CPP
#include <iostream>
using namespace std;
int dp[35][8],n; 
int main()
{
	dp[0][0] = 1;//初始第0行没有尾巴,值为1
	for(int i = 1;i <= 30;i ++)
		for(int j = 0;j < 8;j ++)
			for(int k = 0;k < 8;k ++)
				if(!(j & k) && !((7 - j - k) % 3))dp[i][j] += dp[i - 1][k];//7-j-k:中间没有被占用的格子的二进制状态
	while(cin >> n && n != -1)cout << dp[n][0] << '\n';//输出答案显然不能留尾巴
}
这题的数据范围只有 3030,可以使用打表大法。(当然应该没有人会这么做吧)
CPP
#include <iostream>
using namespace std;
int dp[35] = {1,0,3,0,11,0,41,0,153,0,571,0,2131,0,7953,0,29681,0,110771,0,413403,0,1542841,0,5757961,0,21489003,0,80198051,0,299303201},n; 
int main()
{
	while(cin >> n && n != -1)cout << dp[n] << '\n';
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...