专栏文章
SP3883 题解
SP3883题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqamzfo
- 此快照首次捕获于
- 2025/12/04 01:41 3 个月前
- 此快照最后确认于
- 2025/12/04 01:41 3 个月前
和其他两篇题解的 dp 思路稍许不同,因为有两维且是状压。
正常来说一维可能是不够的,因为有可能枚举到一列时后面一行用 的骨牌铺导致多了个尾巴,那我们就以后面一行尾巴的状态来进行状压。
设状态 表示前 行均填满,第 行多出来的尾巴二进制状态是 时的方案数。比如 的情形如下:

那么还差一个转移方程。 能转移到 有一个必然条件,那就是 和 的与运算必须是 。如果不是 的话,那么必然存在 和 的某一位都是 ,那么中间一个格子会被占用两次,这显然是不合法的。还有一种情况是转移了之后中间一列的格子无法覆盖。在这种情况下,中间一列空出来的值(转化为二进制数)不可能为 。 和 都可以用一张 的骨牌覆盖完。当这种情况也合法的话,状态就可以转移了。
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';//输出答案显然不能留尾巴
}
这题的数据范围只有 ,可以使用打表大法。(当然应该没有人会这么做吧)
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 条评论,欢迎与作者交流。
正在加载评论...