回家路线

一道好题

首先肯定是DP,考虑如何DP

我们发现可以尝试按照乘坐的列车编号的序列进行DP

f[i]表示某种列车序列,最后一趟车是第i个班次的最小花费

那么显然有f[i]=f[j]+A(piqj)2+B(piqj)+C

打开之后发现有ij的乘积项,所以想到斜率优化

移项后变成2Apiqj+fiApi2BpiC=fj+Aqj2Bqj,其中要求yj=xi,qjpi

考虑如何优化,我们肯定要将原来的列车班次进行某种排序,然后进行线性DP

这里肯定要么按照p排序,要么按照q排序(因为时间这一维度是具有单调性,而如果按照x或者y排序,由于x>y就很难发现单调性)

我们先按照q排序,不难发现是维护斜率单调递增

我们把每一个已经DP好了的f[i]按照其y值放在对应的单调队列里面(也就是一共有n个单调队列),在计算某一个f[i]的时候,我们只需要在xi对应的单调队列里面去查找即可

这样就对了吗?

其实是不行的。首先,2Api显然不一定单调,所以我们要用二分,而且还要先用二分在这个单调队列里面查找出来满足qjpi的位置;其次,可能存在一种情况,如下

如图所示,4号点的进入会将3号点弹出去,但有可能3号点是满足qjpi的最大位置,那么3号点是有可能成为最优决策的

那么解决这个的办法是什么?我们就选择不弹出某个点,而是记录某个点如果进行普通的斜率优化的单调队列的话,他的前一个点是哪一个点,设为t[i]。假设新进来一个点,我们就比较这个点和当前单调队列的最后一个点的斜率与当前单调队列的最后一个点和其t(设这个点为x)的斜率大小来决定是否“弹出”当前单调队列的最后一个点(注意我们并不会真的弹出当前单调队列的最后一个点);如果要“弹出”,那么就继续比较新进来的这个点和x的斜率与x和其t的斜率来决定是否“弹出”x,依次类推。不难发现时间复杂度仍然正确(相当于还是每个点最多进队出队一次)。但是这个做法对后面的二分查找就很麻烦了,我只想到了倍增

提醒一下,如果某一趟班次的x=1,这一趟班次不一定非要放在第一个,我们可以先做其他车,最后回到1号站,然后再作这一趟班次,可能时间会更优

以上解法是对q排序,但是代码很难写,那么我们尝试对p排序

此时对p排序之后,就解决了斜率不是单调递增的问题(指解决的这个问题:“首先,2Api显然不一定单调,所以我们要用二分”)

然后仍然需要满足yj=xi,qjpi

第一个条件的处理跟之前一样,就不赘述了

问题是第二个条件的处理

我们想的是某一时刻,当我们更新f[i]的时候,对应的单调队列的所有点都可以用,就可以忽略第二个条件了

为了达到这种效果,我们更新了f[i]之后,不要马上把f[i]插入其对应的单调队列,而是选择放到一个桶里面(对应这一趟班次的q值);然后我们在每次更新f[i]之前,先把所有小于等于pi的桶里面的班次全部插入到对应的单调队列里面就好了

update 2024.7.6

重新做一遍这个题目,已经把状态给想出来,但是却没能想出按照某种顺序排序从而进行线性DP(想的是利用记忆化搜索),就是因为没有写出所有限制条件,所以以后一定要把所有限制条件写出然后排序线性DP啊

说一下心路历程:

最开始设f[i][j]表示在时刻j1号站到i号站的最小烦躁值,显然复杂度爆炸,但是在推导的过程中发现我们似乎不用设置时刻j因为小猫不能自己走,只能通过坐车的方式到达站,所以时刻的信息可以通过两个班次的p,q值来反映,于是改变状态设f[i][0/1]表示从1号站到班次i的起/终点的最小烦躁值(根据上文分析,由于时间反映在班次里面,所以不妨认为这个烦躁值是在这个班次的p,q时刻达到的),不难发现f[i][0]=f[i][1](因为坐车不增加烦躁值),所以可以设出f[i]

update 2024.9.11

重新做了一遍,做出来了

当然中间的转移也可以用李超线段树,但是也要利用“不要更新完就插入”的技巧

posted @   最爱丁珰  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示