CF1131G Most Dangerous Shark

容易根据数据范围得到状态 \(f_i\) 表示只考虑前 \(i\) 个牌并推倒前 \(i\) 个牌的最小代价。原因是这样转移没有啥后效性。

从每个点开始 \(dp\),可以得到如下式子:

  • 向左推倒第 \(i\) 个骨牌,由于最多只能推倒 \(l_i\)\([l_i,i)\) 这些是可以选择性在 \(i\) 之前推的,所以这部分答案为:

    \[\min\{f_j|l_i-1\le j< i\}+c_i \]

  • 不推倒第 \(i\) 个骨牌,那么必须由前面的某个骨牌向右推倒,答案为:

    \[\min\{f_{j-1}+c_j|j<i\le r_j\} \]

发现第一个转移可以优化为 \(f_{l_i-1}+c_i\),具体原因可以证明:

  • 若最优解是从 \(i\) 向左推,但是从 \(l_i-1\le j<i\) 的点也需要推动,那么只有 \(i\) 的后缀的那一部分向右倒才可能更优,与假设矛盾,所以可以优化这个转移。

用单调栈维护 \(l_i,r_i\) 是简单的,具体来说就是 \(i\) 能推倒 \(i+1\) 就把 \(i+1\) 加入,否则就退栈并赋值直到能加入或者栈空。

接下来考虑怎么优化,这个推牌的 \([i,r_i]\) 是很有意思的,根据 \(l_i,r_i\) 的求法我们发现任意两个区间只可能是包含或者相离的关系。所以我们把这个包含关系转化成树上的父亲儿子关系。那么这些个区间就会形成树,我们要求的值也就是到根的链的最小值。看看怎么做。

我们可以在从左向右走到这个点的时候将其加入树,集体来说就是加入这个点本来对应的区间的儿子,然后两个区间对应的值取 \(\min\),如果离开了这个区间,那么就一直跳父亲直到可以容下下一个点。然后继续取 \(\min\)

posted @ 2025-11-20 19:01  NeeDna  阅读(8)  评论(0)    收藏  举报