『学习笔记』动态规划优化

引入 - 数字三角形

三角形矩阵(?),从上往下走使得走过的数的和最大。

  • 状态:通常用 \(f(s)\) 表示状态。其中 \(s\) 为状态的内容,\(f\) 为状态的值,此题中 \(s\) 即为坐标 \((x,y)\) 记录当前走到哪里。
  • 起始状态:可以直接根据题意得到值的平凡情况。此题中 \(f_{1,1}=a_{1,1}\)
  • 转移:一个状态的值需要由哪些状态的值计算得到,可以看作一张有向图的形式。有两种方式:主动转移与被动转移。
    • 被动转移:对着还未算出值的状态直接思考怎么计算,又称填表法。此题中即 \(f_{x,y}=\max\{f_{x-1,y},f_{x-1,y-1}\}+a_{x,y}\)
    • 主动转移:用已经算出值的状态思考能对之后的哪些状态做出贡献。此题中即 \(f_{x,y}+x_{x',y'} \to f_{x',y'}\)
  • 转移方程:状态之间的定量关系。有了状态和转移,转移方程就比较好列。但是需要优化转移时,需要提前列出状态转移方程。

数据结构优化

CF115E Linear Kingdom Races

\(f_i\) 为只考虑前 \(i\) 段赛道的答案。两种情况:

  • 修第 \(i\) 段;
  • 不修第 \(i\) 段。

考虑枚举最后一个修赛道的连续段。则 \(f_i \gets s_i+\max\{f_j+\sum{p_k}-\sum{w_l}\}\)

\(w_i\) 即花费,可以前缀和;\(\sum p_k\) 的条件为 \(j<l_k,r_k\le i,j <l \le i\),即为二维偏序。

P7867

ARC071F Infinite Sequence

给定 \(n(1 \le n \le 10^6)\),求满足以下性质的无穷数列 \(a\) 的个数。

  • \(a_i \le n\)
  • \(n\) 项之后均与 \(a_n\) 相同。
  • 每个 \(i\) 满足 \(a_{i+1}=a_{i+2}=\dots=a_{i+a_i}\)

易得若 \(a_i>1 \and a_{i+1}>1\)\(a_{i+1}=a_{i+2}=\dots\)

先确定前 \(n\) 项中哪些为 \(1\),哪些不为 \(1\),在考虑不为 \(1\) 的位置的方案数。

如果一个非 \(1\) 数后面有 \(x\)\(1\),这里有 \(x-1\) 中方案。

对于最后一段,由一个非 \(1\) 数之后跟着相同的任意数组成,有 \(n(n-1)\) 种方案。

有一种特殊情况是全部为 \(1\)

\(f_i\) 为第 \(i\) 项不为 \(1\) 时前 \(i-1\) 项的方案数之和。

  • 特殊情况:前 \(i-1\) 全为 \(1\)
  • 枚举最后一段 \(1\) 有多长,算上之前最后一个不是 \(1\) 的数的方案。

转移方程即为:\(f_i=1+\sum\limits^{i-2}_{j=1}(i-j-2)f_j\)

答案为 \(1+n(n-1)\sum\limits^{n-1}_{i=1}f_i+(n-1)f_n\)

对于转移,前缀和即可线性。

ARC073F Many Moves

有两个棋子初始在 \(A\)\(B\) 处,有一个长为 \(n(1 \le n \le 2 \times 10^5)\) 的操作序列,形如把一个棋子移到 \(x_i\),求最短移动距离之和。

\(f_{i,j}\) 表示前 \(i\) 个操作,另一个棋子在 \(j\) 的答案。

  • \(j\neq x_{i-1}\),则上一步一定是将位于 \(x_{i-1}\) 的棋子移到 \(x_i\)
  • \(j=x_{i-1}\),则上一步移动的是另一个棋子,即 \(f_{i,x_i-1}=\min\{f_{i-1,j}+|j-x_i|\}\)

前者整体加,后者拆开绝对值后线段树维护。

类似 CSP-S 2024 T3。

P4577 [FJOI2018] 领导集团问题

离散化,记 \(f_i\) 为选择 \(i\)\(i\) 子树内最多选几个,\(g_{i,j}\)\(i\) 不选时 \(i\) 子树内选择点权最小值 \(>j\) 最多选几个。但不好转移。

\(f_{i,j}\)\(i\) 子树内最小点权为 \(j\) 最多选几个。对于 \(i\),合法的 \(j\) 数量不超过子树大小。这样就可以逐个合并所有子树了。

线段树合并优化,维护坐标为 \(j\),结点维护区间中 \(f_{u,j}\) 最大值。


斜率优化

问题:转移方程 \(f_i=\min\limits_{0 \le j < i}\{g_i+h_j+w_iv_j\}\)

暴力是 \(O(n^2)\) 的,考虑优化。

首先,\(g_i\) 可以移到外面去:\(f_i=g_i+\min\limits_{0 \le j < i}\{h_j+w_iv_j\}\)

可以注意到 \(\min\) 中是一个关于 \(w_i\) 的一次函数。

截距优化

点出 \((-v_j,h_j)\),求下凸包,然后二分。或者李超线段树标记永久化。

P4072 [SDOI2016] 征途

将长度为 \(n(n \le 3000)\) 的正整数序列分为 \(m\) 段,使得每段的和的方差最小。

方差等于平方的均值减去均值的平方。

\(f_{i,k}\) 表示序列前 \(i\) 个数分成 \(k\) 段时,最小的 \(\sum\limits^k_{j=1}s_j^2\)。枚举最后一段左端点被动转移。

\(p_i\) 为前缀和,则 \(f_{i,k}=\min\limits_{j\le i}\{f_{j,k-1}+(p_i-p_j)^2\}\)

\(f_{i,k}=\min\limits_{j\le i}\{f_{j,k-1}+p_i^2+p_j^2-2p_ip_j\}\)

  • \(g_i=p_i^2\)
  • \(h_j=f_{j,k-1}+p_j^2\)
  • \(w_i=p_i,v_j=-2p_j\)

\(-v_j,w_i\) 均递增,那么凸包可以单调队列,且取到答案的点也在不断向右移动。队首的点不是答案之后可以删去。时间复杂度 \(O(nm)\)

P4655 [CEOI2017] Building Bridges

\(f_i\) 表示不拆 \(i\),前 \(i\) 个费用之和最小值。设 \(s_i\) 为拆除前缀和。

\(f_i = \min\limits_{j<i}\{f_j+s_{i-1}-s_{j+1}+(h_i-h_j)^2\}\)

\(w_i=h_i,v_j=-2h_j\),斜率优化。

但是 \(h_i\)\(h_j\) 没有单调性。所以只能动态凸包加点然后二分斜率。

但是可以李超线段树维护半平面交轮廓。

对横坐标建立线段树,永久化一个直线标记,不维护任何值。

两个标记相撞时,若横坐标区间内不相交,留下下方那一条;否则保留无交点的那个区间下方的直线,将另一条直线下传给交点所在区间。


优化状态

P8916 [DMOI-R2] 暗号

\(f_{i,j,c}\) 为子树 \(i\) 内黑色点权和为 \(j\)\(i\) 颜色为 \(c\) 时子树内边的得分之和的最大值。

考虑每个点的点权会贡献几次。每个点到根的链上每有一对相邻的同色点且颜色与这个点相同时就会贡献一次。

那么设 \(f_{i,j,k,c}\) 为子树 \(i\) 中,点 \(i\) 颜色为 \(c\),且假设 \(i\) 到根的链上有 \(j\) 对相邻黑色点,\(k\) 对相邻白色点时,子树内所有点的点权对得分的总贡献的最大值。

状态 \(O(n^3)\),单次转移 \(O(1)\)

P6758 [BalticOI2013] Vim

\(f_{i,j}\) 为当前光标位置 \(i\),且 \(j\) 之前满足要求,至少多少操作。枚举接下来是回去删还是往后跳。

优化。上面的状态是按时间顺序考虑的,现在考虑区间关系。

对于任意分界线,最多用 f 经过两次。

\(f_{i,j,k}\) 为在第 \(i\) 位,第一次用 f 经过之前选了字母 \(j\),第二次选了 \(k\) 的情况下,第 \(i\) 位前面部分对答案的最小贡献。当 \(k=0\) 表示只经过了一次。

P7606 [THUPC2021] 混乱邪恶

把三角网格改成二维坐标,然后记 \(f_i,x,y,l,g\) 为是否能使用前 \(i\) 个物品,在三角网格里走到 \((x,y)\)\(L=l,G=g\)

考虑优化状态的复杂度,随机打乱 \(n\) 个物品,那么在三角形网格上行走并回到原点所走到的范围就大概路在 \(O(\sqrt n)\) 内。bitset 优化即可。

ARC070E NarrowRectangles

\(n(n\le10^5)\) 个长方形,第 \(i\) 个的横坐标范围为 \([l_i,r_i]\),纵坐标范围为 \([i-1,i]\)。水平移动这些长方形,使得第 \(i\) 个与第 \(i+1\) 个长方形有公共点,求最短移动距离和。

\(f_{i,j}\) 为把第 \(i\) 矩形的左端点移到 \(j\),前 \(i\) 个矩形移动总距离最小值。复杂度巨大。

考虑每个 \(f_{i,*}\)\(f_{1,j}=|j-l_1|\) 是一个绝对值函数。然后考虑 \(f_{2,j}\)。即将原来函数的底往两边拉,再加上一个绝对值函数。两个下凸分段函数相加还是下图分段函数,那么考虑记录每个拐点的斜率变化。由于每一段中两个一次函数相加斜率是相加的,所以可以记录每个拐点前后斜率加了夺少。

对于 \(f_{i,j}\) 来说,\(j=-\inf\) 的位置斜率是 \(-i\)\(j=+\inf\) 的位置斜率是 \(i\)。故斜率一共增加了 \(2i\)

把排名小于等于 \(i\) 的元素全部减去 \(len_i\),大于等于 \(i+1\) 的元素全部加上 \(len_{i-1}\),于是可以用带有全局加标记的对顶堆来维护,这样就能够转移了。

posted @ 2025-01-11 19:44  仙山有茗  阅读(47)  评论(0)    收藏  举报