Codeforces Gym 101630J - Journey from Petersburg to Moscow

题面

高速公路网连接着 nn 座城市且包含 mm双向高速公路,经过第 ii 条高速公路需要支付费用 wiw_i。节日期间当地交管部门推出了一项优惠政策:如果某车在该高速公路网内经过高速公路的条数多于 kk,则该车仅需支付其经过所有高速路中费用前 kk 大的高速路的费用,而对于剩下的高速公路则无需支付对应费用。现节日期间某司机想从 11 地开车前往 nn 地,试问他所需支付的最小费用。

题目链接 (J 题)

分析

我们不妨把费用当作边长来考虑。

首先考虑最终答案路径经过边小于等于 kk 条的情况:此时答案就是原图中的最短路。因为既然边数小于 kk 条,自然享受不了题目中的优惠政策。如果这条路径享受不了优惠政策都比所有能享受优惠政策的路径享受优惠政策后的长度还要短,那么它自然就是原图中的最短路了。

接下来我们只考虑最终答案路径经过边大于 kk 条的情况。我们假设在某条从 11nn 的路径上第 kk 大的边权为 xx,那么在计算这条路径的距离时第 kk 大以后的边权就要全部视作 00。这等效于,我们事先将这条路径上所有的边权都减去 xx,若边权减去 xx 后变为负数(即说明改变边权不属于前 kk 大)则将边权赋值为 00,然后计算该条路径上所有边权和后再加上 kxk \cdot x

在这一基础上,我们可以考虑枚举答案路径中第 kk 大边权的值。即,对于每一种边权 cc,都在原图中将边 ee 的边权 w(e)w(e) 改为 max(0,w(e)x)\max{(0, w(e) - x)}。接着我们在原图中跑一边单源最短路,记 11nn 点的最短路为 dis(n)dis(n),则可得到将边权 cc 当作第 kk 长边的答案 dis(n)+kcdis(n) + k \cdot c。取所有的这些值以及原始图中的最短路长度中最小值即为答案。


更正式地说,我们记原图为 GG,记 GxG_x代表与 GG 包含边相同,但是对于边 eGe \in G 的边权 w(e)w(e)GxG_x 中变为 wx(e)=max(0,w(e)x)w_x(e) = \max{(0, w(e) - x)}。记 d(x)d(x) 代表 GxG_x11nn 的最短路长度,记 f(x)=d(x)+xkf(x) = d(x) + x \cdot k。我们认为答案,也就是所有路径中前 kk 大边权值和的最小值,就是 ans=minx0f(x)ans = \min\limits_{x \ge 0}f(x)

下面给出简要证明(主要翻译自官方题解,链接附于文末):

首先我们证明对任意 x0x \ge 0 都有 ansf(x)ans \ge f(x)。考虑某条路径 pp,令其所经过的所有边权从大到小为 c1c2clc_1 \ge c_2 \ge \dots \ge c_l。若 lkl \le k 显然该命题成立。在对于 l>kl > k 时,我们记 dp(x)d_p(x) 代表在路径 pp11nn 的距离(也就是该路径的长度),并考虑 xx00 增大到 ++\infty 过程中 fp(x)=dp(x)+xkf_p(x) = d_p(x) + x \cdot k 值的变化:

  • x<clx < c_l,对 xx11 将使得 fp(x)f_p(x) 的值增加:
    fp(x+1)fp(x)=i=1l(cix1)+k(x+1)i=1l(cix)kx=kl<0\begin{aligned}
    f_p(x + 1) - f_p(x) & = \sum\limits_{i = 1}^{l}(c_i - x - 1) + k(x + 1) - \sum\limits_{i = 1}^{l}(c_i - x) - kx \
    & = k - l < 0
    \end{aligned}

  • ci+1x<cic_{i + 1} \le x < c_iik+1i \ge k + 1,对 xx11 将使得 fp(x)f_p(x) 的值增加:

    fp(x+1)fp(x)=j=1i(cjx1)+k(x+1)j=1i(cjx)kx=ki<0\begin{aligned}
    f_p(x + 1) - f_p(x) & = \sum\limits_{j = 1}^{i}(c_j - x - 1) + k(x + 1) - \sum\limits_{j = 1}^{i}(c_j - x) - kx \
    & = k - i < 0
    \end{aligned}

  • ck+1x<ckc_{k + 1} \le x < c_k,也就是 k=ik = i,有 fp(x+1)fp(x)=ki=0f_p(x + 1) - f_p(x) = k - i = 0。与此同时有:

    fp(x)=i=1lmax(0,cix)+xk=i=1k(cix)+xk=i=1kci\begin{aligned}
    f_p(x) & = \sum\limits_{i = 1}^{l} \max{(0, c_i - x)} + x \cdot k \
    & = \sum\limits_{i = 1}^{k}(c_i - x) + x \cdot k \
    & = \sum\limits_{i = 1}^{k} c_i
    \end{aligned}

    这恰好就是 pp 上前 kk 大的边权之和。

  • 对于 ci+1x<cic_{i + 1} \le x < c_ii<ki < k,有:fp(x+1)fp(x)=ki>0f_p(x + 1) - f_p(x) = k - i > 0

换句话说,对于某个固定的路径 ppfp(x)f_p(x) 的值都先随 xx 的增大而减小直到 ck+1c_{k + 1} 处出现最小值 i=1kci\sum\limits_{i = 1}^{k} c_i,并在 x[ck+1,ck]x \in [c_{k + 1}, c_k] 内保持该值,接着又随着 xx 的增大而增大。既然 f(x)f(x) 是所有 fp(x)f_p(x) 中的最小值,则 f(x)f(x) 的值不可能超过 ansans,即最终答案的前 kk 大边权之和。

接下来我们进一步证明 ans=f(x)ans = f(x)。我们依然考虑某条路径 pp,令其所经过的所有边权从大到小为 c1c2clc_1 \ge c_2 \ge \dots \ge c_l

  • lkl \le k,则当 x=0x = 0 时, fp(0)f_p(0) 也就是当前路径所有边权之和。
  • l>kl > k,则在上述分析中不难发现 fp(ck)f_p(c_k) 就是当前路径前 kk 大边权之和。

既然 f(x)f(x) 是上述值中的最小值,那么它自然就是所有路径中前 kk 大边权值和的最小值,即我们要求的答案 ansans

复杂度:O(m2logn)\mathcal{O}(m^2\log{n})

实现

据说这道题卡了 SPFA,所以最好用堆优化的 Dijkstra。

改变边权可以考虑在进行 Dijkstra 时进行,这样更容易实现。

完整参考代码

%%%

This blog is under a CC BY-NC-SA 4.0 Unported License.
Link to this article: https://blog.codgician.pw/2018/10/09/codeforces-gym-101630j/