一道挺妙的题-CF671E

CF671E-%你赛T4

题意:

有 \(n\) 个点按照 \(1,2,\dots,n\) 的顺序排列。对于每个 \(i \in [1,n-1]\),点 \(i\) 和点 \(i+1\) 之间的距离为 \(w_i\)。

每个点 \(i\) 有一个非负整数 \(g_i\)。每当车辆到达点 \(i\) 时,会立即获得 \(g_i\) 单位燃料。车辆的油箱容量没有限制,每行驶 \(1\) 单位距离消耗 \(1\) 单位燃料。

你可以额外分配至多 \(k\) 单位燃料。

对于一对满足 \(1 \le l \le r \le n\) 的点 \((l,r)\),进行如下两个相互独立的阶段:

  • 第一阶段中,车辆从点 \(l\) 出发,只向右行驶,依次经过

\[l,l+1,\dots,r; \]

  • 第二阶段中,车辆从点 \(r\) 出发,只向左行驶,依次经过

\[r,r-1,\dots,l. \]

每个阶段开始时,车辆的油箱均为空,并立即获得该阶段起点处的燃料。之后,每到达一个点,也会立即获得该点的全部燃料。

若在两个阶段中,车辆都能在燃料耗尽之前到达终点,则称区间 \([l,r]\) 是可行的。

区间 \([l,r]\) 的价值定义为

\[r-l+1. \]

请你合理分配至多 \(k\) 单位额外燃料,并选择一个可行区间,使其价值最大。

做法:

记 \(sumg_i\) 表示油量的前缀和, \(sumw_i\) 记为距离的前缀和。

首先考虑从 \(l\) 行驶到 \(r\) 的最优策略 , 先考虑最少分配多少燃料才能到达 \(r\) 。

假设途中路过一点 \(i\) ,那么:

获得的油量:

\[sumg_{i-1}-sumg_{l-1} \]

油耗:

\[sumw_{i-1}-sumw_{l-1} \]

如果某一点 \(j\) 时获得的油量小于油耗,就需要在之前某个点添加油。

为了便利以后从 \(r\) 返回 \(l\) 的时候且不浪费油(从 \(r\) 返回时油量会清零),添加油的点一定是 \(j-1\) ,且添加的油量一定是刚好够车行驶到 \(j\) 。

那么我们就会发现,对于固定的左端点 \(l\) ,放置油的点也一定是固定的,如:

然后我们考虑从右端点返回时的最优策略。

显然我们肯定会把能添加的油都添加到右端点 \(r\) 上。

那么应该至少添加多少油呢?

假设在 \(r\) 添加的油量为 \(t\) ,从 \(l\) 走到 \(r\) 后每个点添加过后的总油量为 \(g'\) ,新的 \(g'\) 前缀和数组为 \(sumg'\) , 添加的总油量为 \(c_r=sumg'_{r-1}-sumg_{r-1}\)。

途中路过一点 \(i\) ,那么:

获得的油量:

\[g_r+t+sumg'_{r-1}-sumg'_{i} \]

消耗的油量:

\[sumw_{r-1}-sumw_{i-1} \]

那么对于每个 \(i\) ,都需要有:

\[g_r+t+sumg'_{r-1}-sumg'_i\ge sumw_{r-1}-sumw_{i-1} \]

即:

\[g_r+t+sumg'_{r-1}-sumw_{r-1}\ge sumg'_i-sumw_{i-1} \]

也就是说:

\[g_r+t+sumg'_{r-1}-sumw_{r-1}\ge \max_{l\le i \le r}(sumg'_i-sumw_{i-1}) \]

那么在顺利返回的前提下,\(t\) 的最小值为:

\[\max(0,\max_{l\le i \le r}(sumg'_i-sumw_{i-1})-g_r-sumg'_{r-1}+sumw_{r-1}) \]

所以总消耗的分配油量:

\[c_r+\max(0,\max_{l\le i \le r}(sumg'_i-sumw_{i-1})-g_r-sumg'_{r-1}+sumw_{r-1}) \]

由于 \(c_r=sumg'_{r-1}-sumg_{r-1}\) ,所以 \(sumg'_{r-1}=sumg_{r-1}+c_r\) ,代入替换,得:

\[c_r+\max(0,\max_{l\le i \le r}(sumg'_i-sumw_{i-1})-g_r-sumg_{r-1}-c_r+sumw_{r-1}) \]

合并 \(g_r,sumg_{r-1}\) 得 \(sumg_r\) 并将 \(c_r\) 传入 \(\max\):

\[\max(c_r,\max_{l\le i \le r}(sumg'_i-sumw_{i-1})-sumg_{r}+sumw_{r-1}) \]

这个式子要小于 \(k\) 。

至此我们整理一下思路。

已知:

  • 对于某一个左端点 \(l\) ,\(sumg'\) 是固定的。在此基础上,对于每个右端点而言 \(c_r\) 也可以被确定。

  • 对于某个区间,判定是否合法只用判断总消耗的分配油量是否小于等于 \(k\) 。

  • 我们要找到最长的一个区间使得它合法。
    那么我们就有一个思路:

对于每个左端点,找到最靠右的合法右端点。

形式化的,设 \(A_i=sumg'_i-sumw_{i-1}\) ,\(B_i=sumw_{i-1}-sumg_{i}\) , \(C_i=sumg'_{i}-sumg_{i}\)。

对于每个 \(l\) ,我们需要找到最大的 \(r\) ,使得:

\[\max(C_r,\max_{l\le i\le r}(A_i) +B_r)\le k \]

这实质上是两个条件:

  • \(C_r\le k\)

  • $\max_{l\le i\le r}(A_i) +B_r\le k $

对于一个左端点 \(l\) 而言,我们可以维护 \(A,C\) 的最大值,\(B\) 的最小值(假设能维护,后文再说)。然后考虑查询:

如果只考虑 \(C_r\) ,显然很好找到最大的 \(r\) 。

而由于 \(C\) 单调不减,所以假设最大的 \(r\) 是 \(R\) ,那么所有 \(r\in[l,R]\) 都满足条件。

然后我们在这个范围内继续考虑第二个条件:

首先我们注意 \(A_i+B_i\le k\) 恒成立。

这是因为 \(sumg'_i-sumw_{i-1}+sumw_{i-1}-sumg_{i}=sumg'_i-sumg_{i}\)

而 \(sumg'_i-sumg_i=C_i\le C_r \le k\)

那么假设 \([l,R]\) 中 \(A_i\) 的最大值的下标为 \(t\) ,如图:

那么我们就知道了区间 \([l,t]\) 一定合法,由于只询问最长的区间,所以我们根本不需要去管左端点为 \(l\) ,右端点小于 \(t\) 的区间了。

也就是说,我们还需要去找 \([l,r]\) 合不合法,其中 \(r\in[t+1,R]\) 。

而对于这些区间 \(\max_{l\le i\le r} A_i\) 就是 \(A_t\) 。

所以问题就是要求最大的 \(r\) 使得 \(A_t+B_r\le k\) 成立。

这个怎么办呢,就是直接在线段树上二分解决。

此处虽然 \(B_r\) 并不单调,但对于线段树的每个节点,可以存下其管辖区间内的 \(B_r\) 的最小值。然后如果右子树的最小值小于等于 \(k-A_t\) 那就去右端点,如果右端点没查到或者右端点最小值大于 \(k-A_t\) 就去左端点。

那时间复杂度正确吗?没有问题!还是 \(O(n\ log\,n)\) !

如图,假设一直往右走却一直没查询到,这时如果左子树的 \(min\le k-A_t\) 那么就会去左子树,而此时这个区间已经被查询区间 \([t,R]\) 完全包含在内了,也就是说一定能查到值。而如果左子树的 \(min>k-A_t\) 那么根本就不会进入左子树,所以一定是对的。

这样,查询的问题就解决了。

接下来,我们需要考虑当 \(l\) 变化的时候,怎么维护 \(A,B,C\) ,这几个都和 \(sumg'\) 有关,所以主要是需要维护 \(sumg'\) 。

首先,我们需要观察一下对于某个 \(l\) 而言,\(sumg'\) 相比 \(sumg\) 增加了哪些部分。

还是刚刚的那个例子:

对于区间左端点 (记为 \(1\) ,后面依次 \(2,3...\) ),显然:

  • \(1\) 处的加油操作给 \(sumg'_{1-5}\) 都增加了 \(2\) 。

  • \(2\) 处的加油操作给 \(sumg'_{2-5}\) 都增加了 \(4\) 。

  • \(4\) 处的加油操作给 \(sumg'_{4-5}\) 都增加了 \(1\) 。

那么我们发现 \(2\) 处的 \(sumg'\) 的值从 \(4\) 处转移是容易的(后缀加即可)。

\(1\) 处的 \(sumg'\) 的值从 \(2\) 处转移也是容易的。

那么我们根据这样的关系,建立一棵树,具体的,记点 \(i\) 在油箱为空时能够达到的最远点为 \(j\) ,则从 \(i\) 向 \(j+1\) 连一条边。

本例中建出的树是这样的:

这样,就可以在 \(DFS\) 的时候就可以方便的维护 \(sumg'\) 了。

至此,本题结束。

posted @ 2026-09-23 20:04  wlhao  阅读(27)  评论(1)    收藏  举报