NOI2019
Day1
回家路线
-
这个题目首先显然可以建图,然后跑 DAG 上的最短路,但是边最大为 \(n^2\) ,但是实际上 CCF 造的数据好像很弱,所以这个方法也许能过
-
但是建图后就和正解无缘了,建图是以位置为标准去解这道题,然而你会发现没办法优化了
-
事实上第一眼看这个式子,很明显是个斜率优化,那么考虑最基本的 \(dp\) 式子
-
\(dp_i=\min(dp_j+A*(p_i-q_j)^2+B*(p_i-q_j)+C)\)
-
因为这个图是一个 DAG ,所以没有后效性,可以直接这样 \(dp\)
-
那么一个想法就是对于每个位置维护一个以这里为终点以终止时间为 \(x\) 轴的凸包(就是斜率优化)
-
但是此时有个问题,就是还有个限制 \(q_j\leq p_i\) ,这个怎么解决
-
对于每个 \(i\) 我们要以 \(p_i\) 来做,那么以 \(p_i\) 排序,这里我选择直接扫时间轴(两者等价)
-
那么扫到当前时间时,我们先将之前的 \(q\leq T\) 的路线放到凸包里面,然后做这次询问
-
做完询问,不能直接将当前的路线塞到凸包,我们需要将当前路线塞到一个堆中,堆以 \(q\) 排序
-
这样没处理一个时间时在堆里面一直弹就行了
-
这样既解决了 \(q\leq T\) 的限制,又解决了凸包中的点的 \(x\) 轴需要递增的限制
-
那么就可以愉快的做了
总结
-
斜率优化 dp
-
在写代码的过程注意到维护凸包的时候一定不能直接
push_back
一个点,因为你的右指针可能已经完全不在队尾了,最好的写法是右指针一边移动,一边pop_back
,最后再push_back
-
注意可能出现横坐标相同的情况,此时的斜率需要特判,按照方向赋值
Day2
弹跳
-
这个题目首先一个很明显的二维线段树建图,但是空间会炸,不知道能得多少分
-
我们考虑上述算法的本质,暂时不想数据结构中的图结构,以原来的网格图为基础
-
从起点出发,可以扩展出一些矩形,我们将这些矩形放入优先队列中
-
找出时间最小的矩形出队,开始处理这个矩形
-
对于这个矩形里面包含的点 \(x\) ,实际上这个点的最小距离已经求出来了,因为这个矩形是第一次出队,代表这个点也第一次出队
-
将这个点可以扩展的矩形放入优先队列中,将这个点从图中删除(因为已经扩展了)
-
然后继续按照上述扩展
-
我们发现本质上是 实点 $\to $ 矩形 \(\to\) 实点,而用二维线段树是 实点 \(\to\) 矩形 \(\to\) 虚点 \(\to\) 叶子虚点 \(\to\) 实点
-
那么我们完全可以将转换成虚点和叶子虚点这两个步骤省去,从而将空间压缩下来
-
但是仍然要保证时间的复杂度,所以我们用线段树维护 \(x\) 轴,线段树上每个节点维护一个 \(set\) ,这个 \(set\) 里面维护这一个范围内的点的信息,以 \(y\) 为关键字排序
-
每次处理一个矩形,就先在线段树中找到对应的一段,然后在这一段找到 \(y\) 轴满足限制的一段,然后将这些满足条件的点所对应的一些弹跳装置放入优先队列中等待松弛,然后将这个点在图中删除(这个点显然已经没用了)
-
删除可以体现为从上到下从线段树中删除
-
时间复杂度:\(O(m\log m+(m+n)\log n^2)\) ,空间复杂度 \(O(n)\)
总结
-
线段树优化建图+set压一维空间
-
这启发了我们图并不是一定要建出来的,更重要的是对于这个图我们要怎么去操作,怎么更简便的达到我们的目的