[Ynoi2018]天降之物

本文详细介绍了面对「天降之物」问题时,如何运用分块(根号分治)和启发式合并策略解决难题。文章首先分析了O(n^2 log n)的解决方案,然后逐步优化成O(n^2),最终通过减少log n的时间复杂度优化至O(n^2)。在解题过程中,涉及了并查集、有序数组的维护以及数组间距离的计算。作者分享了源代码,并表达了对题目的感慨。
摘要由CSDN通过智能技术生成

天降之物

题解

只有 ** 出题人才会出这种又难调又卡常的 ** 题。

笔者原先很快奶出了一个 O ( n n log ⁡   n ) O\left(n\sqrt{n}\log\,n\right) O(nn logn)的做法,然后调了一个下午,交上去后死活过不了,只好又优化了半天优化出了一个 O ( n n ) O\left(n\sqrt{n}\right) O(nn ),又调了一个晚上,最后还调了半天块长才过。

首先,看到题面题目名我们应该很容易想到分块,当然,这里准确说应该叫根号分治。
对于每个不同的数,我们都维护一个有序数组,我们的修改操作相当于合并两个有序数组。
如果合并的两个数组都小于 S S S,直接像归并排序一样用指针合并就行了。
如果合并的两个数组都大于 S S S,由于合并是具有永久性的,这种合并当然也是有限的,不会超过 n S \frac{n}{S} Sn次,我们也可以像上面那样暴力合并。
但如果我们合并的两个数组一个大于 S S S,一个小于 S S S呢,这样显然是不能像刚刚那样合并呢。
但是这种一大一小的合并很容易让我们联想到启发式合并,将小的插入到大的里面去。
如何较快地在一个有序数列中插入一个数,明显就是一个 s e t set set的板子嘛。
所以我们可以对每个数都维护一个 s e t set set,前两种操作可以暴力重构 s e t set set,而下面这种就直接将小的 s e t set set一个一个插入到大的里面去即可。

既然是根号分治,我们自然想到需要维护大于 S S S的数组之间的答案,由于合并是永久的,我们大于 S S S的数组也只会增多,或者被合并,不会凭空消失。
所以,当一个数组变得大于 S S S时,我们可以 O ( n ) O\left(n\right) O(n)地将整个序列扫一遍,维护它与其它数组间的答案,这个只需要从左到右一次和从右到左一次,分别记录下距离每个点最近的属于该数组的点即可。
当两个大于 S S S的数组合并时,我们只需将它们的答案暴力合并即可。
当一个较小的数组插入到另外一个大于 S S S数组里面去时,我们同样可以对于插入的每一个点维护它与其它数字的距离。
由于每一个数只会插入到一个大于 S S S的数组一次,所以每个数自然也只会维护一次。
同样,如果求答案时是两个大于 S S S的数组,我们直接将我们记录的答案输出即可,如果存在小于 S S S的数组,我们可以就对于这个小数组的每个数看看它与另外一个的距离。

至于维护序列中的每个数现在应该是什么,我们可以采用并查集。
每次将 x x x连到 y y y上面后我们都新开一个节点,表示现在值为 x x x,先前值为 x x x的节点都连到 y y y上去了,而之后还会有其它值变成 x x x

容易发现,上面这种做法是时间复杂度是 O ( ( n − x ) n S + x n − x S l o g   S + n S l o g   S ) ⩾ O ( n n l o g   n ) O\left(\frac{(n-x)n}{S}+x\frac{n-x}{S}log\,S+nSlog\,S\right)\geqslant O\left(n\sqrt{n}log\,n\right) O(S(nx)n+xSn

题目 P5413 "YNOI2019 骑单车" 是一个经典的动态规划和贪心算法的问题。该题主要涉及两个概念:路径规划和状态转移方程。 **背景描述** 假设你在一个二维网格上,每个单元格代表一个地点,你需要从起点出发骑车到终点,并尽可能地减少骑行时间。网格中的每个单元格都有两种可能的状态:平地(速度不变)或斜坡(速度减半)。你的目标是找到一条最短的路线。 **关键点解析** 1. **动态规划**:通常用于求解最优化问题。在这个问题中,我们可以定义一个二维数组 dp[i][j] 表示从起点到位置 (i, j) 的最短行驶时间。状态转移方程会根据当前位置的性质(平地还是斜坡)以及到达此位置的最短路径来自之前的节点计算。 2. **状态转移**:对于平地,dp[i][j] = dp[pi][pj] + cost,表示直接移动到相邻位置的时间;对于斜坡,dp[i][j] = min(dp[pi][pj], dp[pi][pj-1]) + cost/2,因为斜坡速度减半,所以需要选择更早的时刻经过。 3. **贪心策略**:有时候,为了达到全局最优,初始看起来不是最优的选择可能是正确的。但在这个问题中,贪心策略可能并不适用,因为我们不能仅依据当前状态做出决策,需要考虑到整个路径。 4. **边界条件**:初始化 dp 数组时,起点时间设为 0,其余位置设为正无穷大,保证一开始就只会向可达的位置移动。 **代码实现** 实现这样的动态规划算法通常需要用到一个优先队列(如最小堆),以便于高效地查找之前节点的最优时间。 **相关问题--:** 1. 如何设计状态转移方程来处理平地和斜坡的情况? 2. 这个问题是否存在剪枝操作以提高效率? 3. 如果网格大小非常大,如何避免存储所有 dp 值导致的空间爆炸?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值