[CF1201D] Treasure Hunting 题解

你谷 link

CF link

题解区有一半是 \(\mathcal O\left(n\log n\right)\) 做法,剩下两篇 \(\mathcal O\left(n\right)\) 做法,跑得又慢,代码还又臭又长,活生生整出大模拟的味道,明明是可以写的很简洁的代码。

在下莽某人不才,暂时拿下你谷最优解:

正片开始

废话到此为止,接下来讲做法,其实大家题解里做法都已经讲得比较清楚了,我这里还是再讲一遍。

给定一张网格图以及一些特殊点和特殊列,只允许向左右走或在特殊列向上走,问经过所有特殊点的最短路径长度。

第一眼就是 dp,感觉就很对,先设一个 dp 状态 \(f_{i,j}\) 表示已经经过所有前 \(i\) 行特殊点,走到第 \(i\) 行第 \(j\) 个特殊点,所经过的最短路径长度。

转移方程就不写了。

然后发现光状态就有 \(\mathcal O\left(n^2\right)\) 个,铁定爆炸,所以考虑做一点优化。

首先肯定从状态入手,发现要经过全部的特殊点,那么在一层内移动方式已经固定了,到达这一层后,要么先走到最左边的特殊点,再往右边走到最右边的特殊点,要么反过来,中间的点可以忽略不计。

这下简单了,每层只记最左边和最右边的点就可以了,时间复杂度瞬减一个 \(n\)

大体思路上就是这样,但是细节还是有的。

首先,如果有空行,那么所有信息应该继承上一行的。

其次,纵向上不一定是走 \(n-1\) 步,顶端如果有空行,注意不用跑到第 \(n\) 行,应当将 \(n\) 设为最靠上的特殊点的纵坐标。

然后就是一点小分类讨论,比如从 \((1,1)\) 走到 \((2,3)\) ,如果第 \(1\) 列到第 \(3\) 列中有特殊列,那么横向移动距离就是 \(3-1=2\),否则的话应该找最近的特殊列去“借道”,比如如果第 \(5\) 列是特殊列,那么横向移动距离就是 \(5\times2-3-1=6\),所以要先预处理每一列左右两边最靠近的特殊列,这样就可以做到 \(\mathcal O\left(1\right)\) 查询,否则如果用二分会变成 \(\mathcal O\left(n\log n\right)\)

最后是代码,自认为还挺简洁的,跑的也不错。

posted @ 2022-03-21 10:24  老莽莽穿一切  阅读(83)  评论(0编辑  收藏  举报