AT_abc379_g

过于一眼的轮廓线 dp。
兼纪念 abc 首场无伤 AK。

首先我们可以经过缜密的计算的得到矩形的宽不超过 \(14\)

然后现在你有 \(4\) 个数(边界视作 \(0\))。
不难想到 \(4\) 进制状压轮廓线 dp。

轮廓线 dp

状压 dp 的一种,轮廓线是分隔已处理部分与未处理部分的线。

在本题中,轮廓线应形如这样:

将轮廓线上的点从左到右压在二进制位从低到高位上。
转移时枚举交界(那个黑色的拐点)的状态判断转移的合法性进行转移。

由于显然有很多无用状态直接用 map 存 dp 状态和值。

那么在 \((i, j)\) 格子处我们要考虑上面和左面(若 \(j = 1\) 则不需)的格子判断转移是否合法。
提取上面的值:up = (sta >> ((j - 1) * 2)) & 3;
提取左面的值:lf = (sta >> ((j - 2) * 2)) & 3;

枚举填什么数(\(k\)),注意还有题目要求的限制。
mp[i][j] == '?' || mp[i][j] == '0' + k

在转移合法情况下,我们从当前状态 \(sta\) 得到下一个状态 \(nxt\)
提取出无关状态,然后把我们枚举的数塞进去:

int Base = (1 << m) - 1;
// ...

int tmp = Base ^ (3 << ((j - 1) * 2));
int nxt = (sta & tmp) | (k << ((j - 1) * 2));

然后计数 dp 正常转移,由于转移只与上一轮廓线有关可以滚动数组。

Code

posted @ 2024-11-09 21:57  KinNa_Sky  阅读(32)  评论(3编辑  收藏  举报