插头dp
基于轮廓线dp。
插头:我们当前会有一条轮廓线,这个轮廓线上有\(m+1\)个数,然后我们状压压的就是轮廓线上有没有插头。就比如说 _____,然后每根线上如果存在插头的话,那么方向就是固定的
_____|
我们的轮廓线最好是逐格转移,这样我们每转移到新的一个就至多有2个插头。然后我们的状态是直接滚动的,那么我们就已经知道轮廓线的形态了。然后我们插头必然是两两匹配的,就是和括号匹配差不多,嗯。那么我们就有左插头和右插头之分,我们就有了三进制数,但是直接写三进制也不麻烦吧?还是另有原因?哦,有一个优化,就是合法的状态不会太多,然后直接哈希表存一下即可,这个东西可能要学一下。
对于[P5056]
分讨!
先设一点东西:\(p1\)为这个格子左边那根轮廓线的插头,\(p2\)为这个格子上边那根轮廓线的插头
如果当前格子为障碍,不可以转移
\(!p1\&\&!p2\) 那么就是必须要这个格子新建一个下插头和右插头
\(!p1||!p2\) 有一个不为零,一个右插头或者一个下插头。
这个插头的状态不会改变
\(p1=p2=1\) 都是左边那个插头,可以连起来,不影响
我们把这个连起来了之后,那么右边和这个匹配的就变成了1
\(p1=p2=2\) 和上面同理
\(p1=2,p2=1\) 也可以,容易理解
\(p1=1,p2=2\) 画下图,我们这样连的话直接断子绝孙了,也就是这根线不能再连下去,因为只有一条回路,容易理解吧,感性一下。如果还有其他可以连,首先,前面的肯定已经匹配完,这根线其他不会有连出去的了。嗯
然后就是代码了,这个感觉就是细节局啊,不难写。
总之,我们先有一个哈希表,然后存的是每个状态,然后状态里面有方案数。这个东西是怎么实现的呢?就是相当于我们可能哈希冲突,那么我们就把所有值都存下来,因为这个查询的密度还是挺大的,所以不能普通哈希。这个时间是状态数/模数。因为模数是随机的,或者是什么一些奇怪的数学同余。所以不太容易被卡掉。我们看看哈希值。
然后可以拓展到多维,我是不是发明新算法了。
[P1713]
逆天,我刚学搜索做的。
首先最小值直接bfs,然后我们就是要找一条从左下角到右上角的路径,我们变一变,变成从左上角到右下角的路径。首先我们的最大值不能记忆化,记忆化的话还得把棋盘压进去。
还是轮廓线dp
在开头,我们只能放进只有一个下插头的状态和只有一个右插头的状态,然后结尾只能从有一个插头,然后中间只要联通就可以了,这样一定是合法的。
如果这个是障碍,那么\(p1\)和\(p2\)都为0才能转移
\(!p1\&\&!p2\) 我们可以按一个右插头和下插头+1,也可以什么都不做+0
\(!p1||!p2\)一样+1
\(p1==1\&\&p2==1\)一样+1
\(p1==2\&\&p2==2\)一样+1
\(p1==2\&\&p2==1\)一样+1
\(p1==1\&\&p2==2\)不能转移
然后就做完了
然后我们要统计的是最长长度,所以转移是+1
有一个值得思考的点是为什么我们插头dp不会出现断的情况,如果出现了,那么在断的那个格子转移必然不合法。
我们考虑bfs做不了的情况是什么,就是我们后来的答案还可能比这个更优。但是我们要证明先到这个的一定更优,一定吧,最短的直接最短路也可以,反正01bfs把
然后这个东西就假了
考虑在外面补一条路径,然后就做完了
原来的做法是对的,但是哈希表写挂了,警钟长鸣
[P1933]
一个路径,还是考虑拆一下,那么就是\(5*52\),然后我们要做\(110\)遍,时间复杂度 \(2^5 * 52 * 110\),可以过。但是有一个比较烦的点就是第\(i\)个参观的展馆有颜色限制,这可能状态还要再多一点。我们可以给每个格子填数,然后还要记录那些数被填过了。其中\(1\)必须填在边上。我们插头也要改一下,我们不仅有左插头和右插头,还有递增插头和递减插头然后我们插头就有\(7\)种状态了,然后我们使用一个什么东西存一下轮廓线上填的数。如果轮廓线上填的数确定了,那么我们已经填的数的集合就确定了。考虑证明这个东西。首先我们有左插头和右插头上填了一点数,然后我们填的数就是这个区间然后就好了!所以我们的状态就是 \(2^{8} * 2^{8} * 2^{8} * 2^{8} * 4^{4} * 4^{4}\)这个东西有\(48\)位,其实\(2^{8}\)只有\(3\)个,用int存下来即可。但是我太懒了,用ull吧。2010年6s,这不随便过。然后我们看下怎么转移状态。是不是只要我们的1填在边界,然后按照l填完就可以了。考虑怎么还原这个东西我们如果有一个单独的插头,容易发现我们单独的插头只能存在第一个插头和最后一个插头,我们每个轮廓线如果不是最后一块我们可不可以。然后每个状态再维护一个bitset看看是否有重复,然后这个可以节约点时间。
一条路径,那么这个左右括号是不是就一点用都没用?
唉,我们直接枚举所有情况,然后把不合法的判掉就可以了。这个感觉比较好判,就是比较容易漏,唉
[P2337]
这个双人博弈啊。感觉有点难搞,看一下数据范围。我们发现这个我们每一层都\(2^12\)枚举炮塔位置,这个是可以的。那么我们设\(dp[st][st1][st2][k]\)第一个是炮塔,我们需要\(2^7\)存下炮塔的位置,\(3^7\)存下插头,\(2^7\)存下上面路径的状态,然后有\(20\)层不过\(5e6\),靠着我们插头dp的超小常数肯定是可以过的。
我们直接
\(dp[st][st1]\)为方案为这个的时候猫猫的最小步数的最大值
我们从所有可行状态转移过来,找一个能使这个最大的东西转移,然后就可以了
完蛋了,已经被自己绕晕了
应该是这样的,如果一个方案有多种线路,那么就取最小的转移,然后方程里是max嗷。