动态规划进阶

\(tD/eD\) 描述动态规划,表示状态数为 \(n^t\),每个状态转移需要依赖之前的 \(n^e\) 个状态,一般复杂度为 \(O(n^{e+t})\)。但我们可以用一些特殊的优化降低复杂度。

单调队列

形如 \(dp_i=\max/\min~dp_j+val_{i,j}\),其中 \(val_{i,j}\) 可以拆开成关于 \(i~j\) 独立的形式。

P5665 [CSP-S2019] 划分

先考虑暴力,设 \(dp(i,j)\) 表示最后一段分割在区间 \([i,j)\) 上,那么最暴力的就是 \(O(n^3)\) 枚举,我们发现 \(dp(j,k) \to dp(i,j)\) 对于每一个 \(j\) 可选的 \(k\) 集应该是不断增大的,于是我们可以对于每一个 \(j\) 单调队列,复杂度 \(O(n^2)\)

其实我们可以配合贪心通过一些数学性质来解决这个问题或者打表,就像方差那题一样。对于这题显然越大的数,平方越大,也就是 \((a+b)^2 \ge a^2+b^2\),于是我们需要保证最后一段划分尽可能小,也就是这么多段尽可能接近或者说划分更多段。

于是我们设出 \(f_i\) 表示前 \(i\) 个数的答案,\(g_i\) 表示最后一段划分的和。这样只需要每次找到最大的 \(j\) 满足 $sum_{j+1,i} \ge g_j $,即 \(pre_i \ge g_j+pre_j\),相同变量在一侧,单调队列即可。注意 \(g_i\) 不一定大于 \(g_{i-1}\),只是要求大于前一段并不是大于上一个位置。

P1776 宝物筛选

多重背包模板题。多重背包最基本的写法是滚动数组设 \(f_j\) 表示前 \(i\) 个物品,体积为 \(j\) 的时候的最大价值,倒序枚举 \(j\) 即可。

\[f_j=\max\limits_{1\le cnt_i\le C_i}\{f_{j-cnt\times V_i}+cnt\times W_i\} \]

\(j=u+p\times V_i\),那么 \(j-cnt\times C_i=u+(p-cnt)\times C_i\),令 \(k=p-cnt \in [p-C_i,p-1]\),有

\[f_{u+p\times V_i}=\max\limits_{p-C_i\le k\le p-1}f_{u+k\times V_i}+(p-k)\times V_i \]

如果感觉不熟悉可以将这里的 \(p\)\(k\) 分别看成经典模型里面的 \(i\)\(j\)

于是我们只需要枚举 \(u\),然后维护一个决策点 \(k\) 单调递减,\(f_{u+k\times V_i}-k\times W_i\) 单调递增减的队列就行了。

带权二分

一篇不错的文章 可惜现在链接好像挂了。

应用场所: 给定若干个物品,要求恰好进行 \(k\) 次操作,最大化或最小化操作后的价值。其实要求 \(\le k\) 次的时候也行,后面会有例题。且代价关于操作次数的函数为凸函数。

特征: 1.一般来说,随着操作次数的增加,价值是单调变化的。 比如操作越多,答案越优。

2.如果不限制选的个数,那么很容易/很快可以求出最优方案。

做法: 虽然我们已知 \(f_n(x)\) 关于操作次数 \(x\) 是凸函数,但是我们并不知道 \(x=m\) 点的函数信息,我们可以通过用一条切线去切它不断获取函数信息。我们可以设每次操作的代价为 \(k\),然后算出来最后的最小价值就是 \(\min\{f(x)-kx\}\),这等价于用一条斜率为 \(k\)\(f(x)\) 相交得到的最小截距,显然是切线的时候截距去极值。由于是凸函数斜率单调,所以我们直接对斜率二分即可。

你甚至可以带权二分套带权二分。

P1484 种树

这题就是操作次数 \(\le k\) 的情况,其实我们可以发现如果操作次数 $ \le k$ 的话那么就相当于没有限制,于是先对 \(c=0\) 跑一遍,如果\(g \le k\) 的话那就直接可以输出答案。如果 \(g > k\) 说明选取 \(>k\) 的时候更优,综合 $g \le k $,可以得出 \(g=k\) 的时候在此条件下最优。于是套上 wqs 二分即可。

P6246 [IOI2000] 邮局 加强版 加强版

小结论:满足四边形不等式的序列划分具有凸性。
有点逆天,如果只是二维决策单调性过不掉,于是先 wqs 二分处理掉 \(m\),然后发现剩下的一维居然还有决策单调性,于是再二分队列一下就行了。

P2619 [国家集训队] Tree I

wqs 二分不仅仅只能用来解决 DP。注意在边权相同的时候,优先选白/黑是根据 check 函数中 \(\le\) 还是 \(\ge\) 来判断的。像我这种写法用 \(\le\) 是要黑边优先的,因为假设我们黑边优先无法达到 \(k\),白边优先可以超过 \(k\),那么在百边优先的情况下,我们会增大白边的边权,然后就会发现百边又不够了,但是不可逆回去,就错了。如果写的是黑边优先,那么我们会让白边权值变小,刚好可以使得原本黑白相等变成,白 \(<\) 黑,这样子就可以满足了。其实我自己发现了一个最小化原则,就是 wqs 二分内部如果要 check \(\le k\) 的话,那么都是要最小化 \(cnt\) 的,优先选黑边可以最小化 \(cnt\)

决策单调性

简述:若 \(dp_i\)\(dp_j\) 转移而来,则称 \(j\)\(i\) 的决策点,记为 \(p_i\)。如果 \(p_i\)\(i\) 的增大而单调不升或不减,则称 dp 满足决策单调性。一般有几种解决方法。

如何判断

四边形不等式

这里主要讲一维的,还是这个式子 \(dp_i=\min\{dp_j+w_{i,j}\}\),当单调队列与斜率优化都不能用的时候,我们就需要考虑四边形不等式优化。若对于任意 \(a\le b\le c\le d\) 都有:\(w(a,d)+w(b,c) \ge w(a,c)+w(b,d)\) 成立,则称 \(w\) 满足四边形不等式。从而 \(dp_i\) 有决策单调性。

上述式子有点抽象,不太好直接拿来套用,更常用的证明形式是对于任意 \(a<b\),有 \(w(a,b+1)+w(a+1,b) \ge w(a,b)+w(a+1,b+1)\)。简单来说就是相交优于包含,优于可以根据最大还是最小取大于或者小于。

证明:在 \(i\) 处有,\(f_{p_i}+val(p_i,i) \le f_j+val(j,i)\)。(其中 \(j<p_i\))。

我们要证的就是在 \(i'>i\) 处,同样满足 \(f_{p_i}+val(p_i,i') \le f_j+val(j,i')\)

等价于去证明:\(val(p_i,i')-val(p_i,i) \le val(j,i')-val(j,i)\)

又因为 \(val\) 满足四边形不等式,所以满足上述式子,故成立。

如果感性观察出四边形不等式?假设我们要最小化 \(f\),首先对于一个点 \(i\) 的决策点 \(p_i\)\(f_{p_i}+val(p_i,i') \le f_j+val(j,i')\),其中 \(val\) 的区间有重叠一段,都是延伸到 \(i'\) 但是不等式右侧的起点 \(j\) 显然是要比左侧的 \(p_i\) 更靠前,故 \((p_i,i)\subset (j,i)\)一般而言右边的大区间的贡献函数是要比其子区间要大的,但是还要比 \(f\) 值,能满足上述式子还要 \(f_j\) 并没有小到甚至可以抵消 \(val\) 的差距。那么我们看待证明的式子,\(f_{p_i}+val(p_i,i') \le f_j+val(j,i')\),唯一区别就是贡献函数在起点不变的情况下终点同时延伸到了另一个更远的地方,还是上述道理,大区间的贡献函数一般是要大于其子区间的,而且一般来说同时增加相同一部分,大区间 \(val\) 的增长速度是要大于等于小区间 \(val\) 的增长速度的(因为大区间本来就有更多的部分来去与增加的一段区间相互作用产生贡献,当然如果每个位置贡献独立的话就是等于了)。所以我们 \(val\) 的差距不仅没有减小,反而增到了,本来就无法填补差距的 \(f\) 这下更没办法填补了。

函数角度

考虑贡献函数,如果是直线直接斜率优化。
一般贡献函数可以通过平移得到,且二阶导非负或者非正。

斜率优化

形如 \(dp_i=\max/\min~dp_j+val_{i,j}\),其中 \(val_{i,j}\) 不能拆开成关于 \(i~j\) 独立的形式,但是可以拆成含 \(i~j\) 乘积项的形式。
最大化,斜率单调递减维护上凸壳。最小化,斜率单调递增维护下凸壳。
其实不是所有的斜率优化都是决策单调性,因为如果插入的横坐标或查询的斜率不单调就不是决策单调性,但依然可以配合 二分,CDQ 分治,李超线段树,二进制分组,平衡树解决。

P3628 [APIO2010] 特别行动队

\[dp_i=\max \left\{ dp_j+a(s_i-s_j)^2+b(s_i-sj)+c \right\} \]

\[\to dp_j+as_j^2-bs_j=(dp_i-as_i^2-bs_i-c)+2as_i \times s_j \]

这几项分别为纵坐标,截距,斜率和横坐标。发现斜率单调递减且要求最大化 dp,所以维护上凸壳即可。

分治

常用于 \(2D/1D\) 动态规划上,或者贡献难算的时候。
同时不能是自转移,必须分层转移。
设目前待决策的范围是 \([l,r]\),决策点在 \([pl,pr]\),对于区间中点 \(mid\),暴力找到决策点 \(p_m\) 然后分治一下 \([l,m-1] \to [p_l,p_{m}]\) 还有 \([m+1,r] \to [p_m,p_r]\)。复杂度为 \(O(nk\log n)\)

P4360 [CEOI2004] 锯木厂选址

首先对于第二个工厂我们有,

\[f_{1,i}=\min(v_j+cost(j+1,i)) \]

不难证明 \(cost\) 函数满足四边形不等式,由于是分层转移,我们直接分治。
最后统计一下答案即可,\(ans=\min(f_{1,j}+cost(j+1,n))\)

还有一个随机化的解法,很有意思,把两个分治点算成二元组 \((x,y)\) 放到平面上,初始平面是 \(n\times n\) 的,随机出来一些点,看看那个更优,然后以最优秀的点为中心缩小平面和减少每次随机出来的点,直到平面足够小,就暴力把每一个点都扫描一遍,找到答案。

二分单调队列

决策点单调不降。
贡献函数二阶导恒为非负,求最小值。或者贡献函数二阶导恒为非正,求最大值。
具体实现方式就是维护一个队列里面储存着若干三元组,\((l,r,x)\) 表示 \([l,r]\) 这一段目前的最优决策点是 \(x\),初始放入 \((1,n,0)\)。每次取队首(绿笔部分)作为 \(i\) 的最优决策点,然后转移完后及时清理,使得队内待决策区间的范围是 \([i+1,n]\),接着我们需要把 \(i\) 作为决策点去更新队列里的决策点,由于我们此前加入了 \([0,i-1]\) 的决策点,所以当前加入 \(i\) 时根据决策单调性理论,修改的应该是末尾的一段 \([p,n]\) 范围内的决策区间。我们从队尾开始对于三元组进行判断,如果对于当前三元组的左端点有 \(i\) 优于 \(x\),那么意味着整个决策区间里都是 \(i\) 更优了,直接弹出队尾(就像图中红笔那样)。然后直到遇到一个区间(图中右数第三个区间)不满足上述要求,那么我们就判断一下该区间右端点是否使得 \(i\) 优于 \(x\),如果成立的话说明一段后缀是可以使得 \(i\) 更优的,我们直接二分一下就可以了,分界点就是蓝色矩形的左边界,然后我们直接把蓝色覆盖区间整体加入即可。

P1912 [NOI2009] 诗人小G

\(s_i=len_i+i\),列出状态转移方程 \(f_i=\min\left\{ f_j+\lvert s_i-s_j-1-L\rvert^p\right\}\),此时可以证明四边形不等式,也可以设出 \(f(x)=\lvert x-L \rvert^p\),去掉绝对值号,两段的二阶导显然非负而且是求最小值,故采用二分队列。

P3515 [POI2011] Lightning Conductor

首先肯定需要正反各做一遍,这里讨论正着做。

\(f_i=\max\left\{a_j+\sqrt{i-j}\right\}\),我们对于贡献函数 \(\sqrt{x}\) 求导发现二阶导小于等于 \(0\),且函数求最大值,所以可以二分单调队列。其实这个决策单调性也可以通过对于四个点 \(i<j<k<z\),若 \(val(i,k)<val(j,k)\),则必然有 \(val(i,z)<val(j,z)\),迅速发现决策单调性。

本题其实不用二分,因为贡献式子特殊,我们可以在 \(O(1)\) 时间内找到转折点。

二分单调栈

非传统决策单调性,每个决策点只会被它更靠前的决策点反超。
贡献函数二阶导恒为非负,求最大值。或者贡献函数二阶导恒为非正,求最小值。
我们可以用单调栈来维护,考虑加入一个新的决策点,如果它已经弱于栈顶了,那么根据上述性质它已经被反超了就没有后续产生贡献的可能了直接出去,但是对比一下单调队列,单调队列是可能被后续的点所取代,所以我们可以在加入后续点的时候来计算能取代哪些点,但是这个单调栈里的是可能被前面点取代,我们不可能每次都遍历一遍栈来看看哪些可以取代前面的吧,所以每次加入一个新决策点的时候,我们都要提前计算一个它前面一个点何时反超自己,每次决策的时候先看当前时间是否已经达到栈顶被反超的时间,如果是的就直接弹出继续判断下一个就行了。

P5504 [JSOI2011] 柠檬

贪心一下,每个选取区间左右端点应该都是该区间所要钦定的贡献颜色,于是有

\[f_i=\max\limits_{c_i=c_j}\{f_{j-1}+c_i\times(sum_i-sum_j+1)^2\} \]

我们要求最大化且贡献函数二阶导非负,所以可以考虑单调栈。

二维四边形不等式的应用

对于状态转移方程 \(F_{i,j}=\min \left\{ F_{i,k}+F_{k+1,j}+w(i,j) \right\}\),如果满足

  1. \(w\) 满足四边形不等式。
  2. 对于任意 \(a\le b \le c \le d\),有 \(w(a,d) \ge w(b,c)\)

那么可得 \(F\) 也满足四边形不等式。
如果 \(F\) 满足四边形不等式,则对于决策点 \(P\) 满足,\(P_{i,j-1} \le P_{i,j} \le P_{i+1,j}\)
在此范围内枚举决策点 \(k\) 即可,for(int k=p[l][r-1];k<=p[l+1][r];k++)

理解一下,我们固定 \(i\),发现是 \(j\) 处的一个寻找最优 \(k\) 的过程,满足决策单调性,所以 \(P_{i,j-1}\le P_{i,j}\)。固定 \(j\) 同理。

P1880 [NOI1995] 石子合并

满足上述式子,直接四边形不等式即可。

P4767 [IOI2000] 邮局 加强版

\(f_{i,j}\) 表示前 \(i\) 个村庄,设置了 \(j\) 个邮局的最小距离和。
\(f_{i,j}=\min\{f_{k,j-1}+w(k+1,j)\}\)
其中 \(w_{l,r}=w_{l,r-1}+X_r-X_{\lfloor\frac{l+r}{2}\rfloor}\),或者前缀和计算。
有点抽象,我以为只有石子合并那个式子才可以二维四边形优化,原来这个式子也可以啊。\(P_{i,j-1}\le P_{i,j}\le P_{i+1,j}\)

Slope Trick

维护一个图像为凸函数的 \(dp\) 信息。一般是 \(dp_{i,j}\),我们发现对于每一个 \(i\),将 \(j\) 作为横坐标,\(dp_i\) 作为纵坐标,形成的是一个凸函数。对于每个 \(i\) 维护一个 \(dp_i\) 关于 \(j\) 的图象。

每次更新肯定是由 \(i'\) 转移到 \(i\),直接在 \(i'\) 的图象上修改得到 \(i\) 的图象。对于每个 \(j\) 显然加入的是一个与 \(j\) 相关的函数。由于一次凸函数的性质只需记录最左端的直线信息以及拐点即可。一个拐点相当于斜率变化 \(1\),如果要变化很大就加入多个相同点。要求:图象为连续的分段一次凸函数。注意:一般绝对值产生贡献的动态规划题目都可以往这方面想。

维护方法:

  1. 合并:最左端一次函数斜率和截距相加,拐点集合取并集。

  2. 寻找最值,找到斜率为 \(0\) 的一段,用大根堆 \(R\) 维护左边分段点,用小根堆 \(L\) 维护右边分段点。两个堆顶即为最大值的左右端点。

  3. 加入一次函数:\(y=x\) ,将 \(R\) 堆顶放入 \(L\) 中。如果加入一次函数斜率较大,可以将修改集合定义为每个位置斜率变化量即差分,修改 \(k\)\(b\) 即可。

  4. \(F\) 函数取前缀 \(\max\) 记为 \(G\), 则 \(G\) 就是 \(F\) 的集合去掉 \(R\)

  5. 平移和翻转:维护 \(k\)\(b\) 变化,分段点打平移或者翻转标记。

CF713C Sonya and Problem Wihtout a Legend

小技巧:令 \(a_{i} \gets a_{i}-i\) 就可以转化为不降了。设 \(f_{i,j}\) 表示第 \(i\) 个数调整为 \(j\) 的最小代价。

\[f_{i,j}=\min_{k=1}^{j} f_{i-1,k}+|a_{i}-j| \]

\(F_{i}(x)=f_{i,x}\) , \(G_{i}(x)=\min_{k=1}^x F_{i}(k)\),可得

\[F_{i}(x)=G_{i-1}(x)+|a_i-x| \]

\(F\)\(G\) 均为凸函数,本题转移和答案都与 \(G\) 有关,这样只需要维护 \(G\) 即可。由上述性质 \(4\) 可得 \(G\) 的最后一段是平的,于是我们只需要维护 \(L\) 堆即可。

加入绝对值函数相当于在 \(a_i\) 处斜率变化 \(2\),于是加入 \(\left\{~a_i,a_i~\right\}\)。观察一下贡献 $x \le a_i $ 部分加上了一次函数 \(a_{i}-x\) 相当于斜率都减 \(1\), \(x \ge a_{i}\) 部分加上了 \(x-a_i\) 相当于斜率加 1。

\(a_i \le L.top()\) 时候 \(L.top()\) 决策点因为斜率增加 \(1\),所以不是平的了,于是 \(L.pop()\) 平线段抬升代价为 \(x=L.top()\) (未 pop 前的值)带入 \(x-a_i\)

\(a_i>L.top()\) 时候第一个 \(a_i\)成为最优决策点,第二个 \(a_i\) 不优所以不插入。而且注意到加入的函数 \(\lvert x-a_i \rvert\) 函数值为 \(0\) 的点一定在平线段的正下方,所以无代价。

CF372C Watching Fireworks is Fun

很显然的 Slope trick 形式,取区间 \(\min\),加绝对值一次函数。

不过先要简化一下,可以先把答案累加 \(\sum b_i\),然后把最小化 \(-\sum\lvert x-a_i\rvert\) 变成最大化 \(\sum\lvert x-a_i\rvert\)

P3642 [APIO2016] 烟火表演

\(F_u(x)\) 表示以 \(u\) 为根的子树中到达时间为 \(x\) 的代价,则有

\[F_u(x)=\sum F_v(k)+\lvert x-k-l_{v \to u}\rvert \]

我们发现了绝对值函数,联系之前 \(dp\) 优化策略可以联想到凸函数优化,数学归纳法可证 \(F_u(x)\) 为下凸函数。

凸优化是需要通过一个堆维护点集,由于需要子节点的向上合并所以可以用到可并堆。

这题转移方程形式和 CF713C 不一样,那题的贡献函数与 \(k\) 无关,\(k\) 可以直接调整至最优,所以可以直接处理出前缀最大值。而这道题贡献函数与 \(k\) 有关,所以我们应该思考对于父节点的 \(x\) 子节点的什么 \(k\) 转移过来才是最优的。

还是记子节点斜率为 \(0\) 那一段左右端点为 \(L\)\(R\)\(x\) 的关系。

\(x \le L\) 时候 \(f_u(x)=f(x-deta)+deta+l_{v \to v}\),考虑 \(f(x-deta)+deta\) 有两种思考方案

  1. 分析函数性质 \(f(x)\) 斜率 \(\le-1\),所以 \(deta=0\) 的时候 \(f(x-deta)+deta\) 取最小值

  2. 思考实际意义,\(deta=0\) 的时候相当于在 \(u \to v\) 这条边上直接修改边权,如果 \(deta>0\) 相当于对于 \(v\) 的每一个子节点进行修改,因为 \(v\) 的子节点个数 $ \ge 1$ 需要修改更多的边,所以对于子节点的边修改显然是需要更大代价。

于是就有 \(x \le L\) 的时候 \(f_u(x)=f_v(x)+ l_{u \to v}\)

其他情况也是类似思考方式。

可以得到

\[ f_u(x) = \begin{cases} f_v(x)+l & x \le L \\ f_v(L)+l-(x-L) & L < x \le L+l \\ f_v(L) & L+l < x \le R+l \\ f_v(R)+x-R-l & R< x \end{cases}\]

思考一下如何转移,第一段是向上平移,第二段是加入一条一次函数,第三段是向右边平移。第四段是将最后的斜率改为 \(1\),原因是由 \(f(R)\) 这个值加上一次函数得到的所以斜率为 \(1\)。其实第三段我们可以不用管因为在处理第二段的时候就相当于将第三段平移过了。可并堆维护即可。

这种复杂函数图象维护可以自己画图感受一下更好。网上有一些这种凸函数维护操作的模板方法,但是实际运用起来却不可照搬,像这题的处理操作就很灵活,和我之前看到的处理模板方法不太一样,每一题需要思考符合题意的维护方式,仔细画图研究,大胆维护。

动态 dp

一般是对于简单树上 dp,带上了修改操作。以下面一题作为例题

P4719 【模板】"动态 DP"&动态树分治

首先是不带修改,\(f_{u,0/1}\) 分别表示选或者不选 \(u\) 点。
\(f_{u,0}=\sum\limits_{v} \max\{f_{v,0},f_{v,1}\}\)
\(f_{u,1}=\sum f_{v,0}+a_u\)
我们发现对于每次修改一个点改的只是一条链上面的结果,于是我们可以采用重链剖分。考虑使用支持快速对于重链修改的方程,增加一个表示 \(g_{u,0/1}\) 分别表示可选可不选或者全部不选。
\(f_{u,0}=g_{u,0}+\max(f_{son,0},f_{son,1})\)
\(f_{u,1}=g_{u,1}+a_u+f_{son,0}\)
\(g_{u,1} \gets g_{u,1}+a_u\),于是有 \(f_{u,1}=g_{u,1}+f_{son,0}\)
\(\begin{bmatrix}g_{i,0}&g_{i,0} \\g_{i,1}&-\infty \end{bmatrix}\)\(\begin{bmatrix}f_{j,0} \\f_{j,1} \end{bmatrix}=\) \(\begin{bmatrix} f_{i,0} \\f_{i,1} \end{bmatrix}\)

这是一个方便在重链上转移的方程,轻链对于重链的贡献,单独修改一次即可。
这里我们动态维护矩阵的值即可,我们发现重链链尾也就是叶子节点上 \(f\)\(g\) 相等,所以后续维护不需要维护 \(f\) 了, 直接用 \(g\) 往上乘就行了。

P4751 【模板】"动态DP"&动态树分治(加强版)

这个需要全局平衡二叉树来实现了。因为矩阵乘法的常数过大。

P8820 [CSP-S 2022] 数据传输

\(dp_{i,0/1}\) 分别表示到 \(i\) 自己或者最小的儿子的最小代价。
分析可知 \(k=1/2\) 的时候走到儿子不优。
\(k=1~~dp_i=dp_{i-1}+val_i\)

\(k=2~~dp_i=\min\{dp_{i-2},dp_{i-1}\}+val_i\)

\(k=3~~ \begin{cases} dp_{i,0}=\min\{dp_{i-3,0},dp_{i-2,0/1},dp_{i-1,0/1}\}+val_i \\dp_{i,1}=\min\{dp_{i-2,0},dp_{i-1,0/1},dp_{i,0}\}+w_i \end{cases} \)
对于 \(k=1/2\),构造矩阵

\(\begin{bmatrix} val_i&\infty&\infty \\ \infty&0&\infty \\\infty&\infty&0 \end{bmatrix}\)\(\begin{bmatrix} f_{i-1}\\0\\0 \end{bmatrix}\)\(=\begin{bmatrix}f_i\\0\\0\end{bmatrix}\)

\(\begin{bmatrix} val_i&val_i&\infty \\0&\infty&\infty \\\infty&\infty&0 \end{bmatrix}\)\(\begin{bmatrix} f_{i-1}\\f_{i-2}\\0 \end{bmatrix}\)\(=\begin{bmatrix}f_i\\f_{i-1}\\0\end{bmatrix}\)

前两个可以轻松用用目前形式矩阵解决,\(k=3\) 的时候 \(5^3\) 可承受不了。
我们发现有些状态是重复的,比如从 \(i\) 跳到 \(i+1\),从 \(i-1\) 或者 \(i_v\) 开始跳距离都是一样的。也就是说在往后跳无论到哪个点,这两个的距离都是一样的,所以可以放在一个状态里。
于是我们考虑优化一下化简一下状态数,可以发现约束条件只与距离有关,所以我们可以将距离放入状态。
于是设 \(dp_{i,0/1/2}\) 表示跳到离 \(i\) 距离为 \(0/1/2\) 的最小值。

\(\begin{cases}dp_{i,0}=\min\{dp_{i-1,0},dp_{i-1,1},dp_{i-1,2}\}+val_i \\dp_{i,1}=\min\{dp_{i-1,0},dp_{i-1,1}+w_i,dp_{i-1,2}+val_i+w_i\} \\dp_{i,2}=dp_{i-1,1} \end{cases}\)

这样子就解决了。我们继续列出矩阵

\(\begin{bmatrix} val_i&val_i&val_i \\0&val_i&val_i+w_i \\\infty&0&\infty \end{bmatrix}\) \(\begin{bmatrix} f_{i-1,0}\\f_{i-1,1}\\f_{i-1,2} \end{bmatrix}=~\begin{bmatrix}f_{i,0}\\f_{i,1}\\f_{i,2} \end{bmatrix}\)

然后我们预处理出向上和向下的转移矩阵幂即可。注意矩阵没有交换律,所以必须分向上和向下解决。
注意题目中说了 \(s_i \neq t_i\),否则需要特判起终点重合。

posted @ 2024-02-11 21:51  Mirasycle  阅读(14)  评论(0编辑  收藏  举报