zyb 的 ABC365F - Takahashi on Grid

题目

link

思考

默认从 x 小的走向 x 大的,因为起点终点反一下不影响。首先感觉可以模拟:能沿 x 轴往下走就往下,不能往下就左右调整到一个最近的缺口处(就是下一层(层指的是 x 轴)的 L i L_i Li U i U_i Ui)。但是问题这样做在 x 轴方向上每次只能走一格,最终复杂度会是 O ( q n ) \mathcal{O(qn)} O(qn)

然后我的想法是将向下走分成两个部分:一、沿着一个单调向右下或左下的坡走;二、没有“一”中的坡,向下飞跃。如左图。但是我们容易想到如右图的情况仍能把我们的做法卡掉。所以我想 dp:就是从上往下扫到第 j j j 层,维护 d p ( i , 0 / 1 , 0 / 1 ) dp(i,0/1,0/1) dp(i,0/1,0/1) 表示从第 i i i 层的左/右端点到第 j j j 层左/右端点的距离。然后考虑到 d p dp dp 可能在一些区间内具有同样的变化方式,所以想用线段树维护 d p dp dp。但是这也是问题所在,确实 d p dp dp 在一些区间内具有同样的变化方式,但是可能的情况是在许多极小的区间都变化不同,而且可能中间状态不能被另一个 d p dp dp 状态表示,导致 d p dp dp 转移极其复杂,反正我没写出来,大概是不可做的吧。

然后了解了一下别人的做法,似乎都和我想的不太一样,但是我看到了倍增,这启发了我。我们可以设计 d p ( i , 0 / 1 , k ) dp(i,0/1,k) dp(i,0/1,k) 表示从 i i i 层左/右端点往下走 2 k 2^k 2k 次的位置和距离。注意,我们走一次并非一层,因为向下飞跃(上一段所述向下走的第二种部分)会得到中间并非左右端点的状态,所以这里压缩掉,直接到最下然后再走斜坡。快速向下走的终点可以用单调栈加二分寻找并维护,进一步,没有向下飞跃的走法也可以包含在这之中。期望复杂度 O ( ( n + q ) log ⁡ n ) \mathcal{O((n+q)\log n)} O((n+q)logn)

解法

我们形式化地讲一下:

调整使起点层数小于终点。从后往前遍历层数 i i i
向下走一次指的是先向下走到底,然后再左右调整到再下一层的区间左右端点( L , U L,U L,U)上。这可以用左侧 L L L 递减以及右侧 U U U 递增的单调栈和二分维护并查找。
设计 d p ( i , 0 / 1 , k ) dp(i,0/1,k) dp(i,0/1,k) 表示从 i i i 层左/右端点向下走 2 k 2^k 2k 次的层数, f ( i , 0 / 1 , k ) f(i,0/1,k) f(i,0/1,k) 表示从 i i i 层左/右端点向下走 2 k 2^k 2k 次在那一层的左( L L L)还是右( U U U)端点( f f f 在转移中需要用到), g ( i , 0 / 1 , k ) g(i,0/1,k) g(i,0/1,k) 表示从 i i i 层左/右端点向下走 2 k 2^k 2k 次的左右水平方向总距离(路程)(这里不算垂直方向,因为最后一起算 ∣ s x − t x ∣ |s_x-t_x| sxtx 简单)。倍增维护。
然后计算起点在 i i i 层的询问:一、将起点向下走一次,这样使我们得到在 d p dp dp 中存在的状态。(注意特判向下走一次就超过终点的情况)二、倍增到层数 ≤ \le 终点层数。三、再加上由“二”得到的最终状态到终点的距离。(可以直接减因为终点与该状态同层或在该状态向下飞跃的区间中)

rec

评价

我为什么没想到倍增,差点就切 abc f 题了?为什么别人的做法都是线段树并且在线(纯看不懂)?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值