[CF2107F1] Cycling (Easy Version)

Cycling (Easy Version)

题目描述

程序员Leo在市中心工作,他的恋人在郊区一所高中任教。每个周末,Leo都会骑自行车前往郊区与恋人共度美好时光。

当前这条路上有n名骑行者位于Leo前方,他们从前到后编号依次为1、2、...、n。初始时Leo位于第n名骑行者后方。第i名骑行者的敏捷值为\(a_i\)

Leo希望超越第1名骑行者。他可以无限次执行以下操作:

  • 假设当前Leo前方第一人是骑行者i,他可以花费\(a_i\)代价移动到骑行者i前方,此时他将位于骑行者i - 1后方
  • 使用超能力交换\(a_i\)\(a_j\)\(1 \leq i < j \leq n\)),消耗\((j - i)\)代价

Leo想知道超越第1名骑行者所需的最小代价。本题只需输出整个数组的最终答案,即\([a_1, a_2, ..., a_n]\)


思路

定义两个操作分别为「超越」和「交换」.

直觉上我们在一定会通过某些交换操作使得当前超越的 \(a_i\) 尽量小, 进而减小代价.

考虑形式化一点的方案, 我们使用一个实例

\[7, 2, 5, 5, 3, 4 \]

对于以上序列, 如果我们要从后往前超到第 \(3\) 个人前面, 一种最优方案是先将 \(a_5, a_6\) 进行交换, 随后每移动一次就以 \(3\) 的代价超越, 同时会产生 \(1\) 的交换代价; 如果我们要超到最前面, 那么最优的方案是先将 \(a_2, a_6\) 进行交换, 然后以每次 \(2 + 1\) 的代价超越.

拿整段来说, 我们令 \(p\) 表示最小的 \(a_i\) 的下标, 那么对于区间 \([1, p]\), 最优的策略一定是带着 \(a_p\) 一路走到 \(1\), 因为 \(\forall i \in [1, p), a_i \ge a_p + 1\). 同时, 对于一段 \([p, q]\), 我们也可以使用 \(a_p\) 进行超越. 具体来说, 我们现在将 \(a_p\) 交换到 \(q\), 然后再一路向前走到 \(1\).

我们设 \(f_i\) 表示当前到达 \(i - 1 \sim i\) 之间的最小代价. 至于转移, 我们令 \(p\) 表示当前中最小的 \(a_k, k \in [i, n]\) 的下标. 然后枚举 \(j \in [p, n]\), 表示将 \(a_p\) 先交换到 \(j\), 再一路向前走到 \(i\), 代价为 \(a_p \times (j - i) + 2 \times (j - p) + (p - i - 1)\).

f[n] = 0;
for (int i = n - 1; ~i; --i) {
    int pos = i + 1;
    for (int j = i + 1; j <= n; ++j) {
        if (a[j] < a[pos]) {
            pos = j;
        }
    }
    for (int j = pos; j <= n; ++j) {
        f[i] = min(f[i], f[j] + a[pos] * (j - i) + 2 * (j - pos) + (pos - i - 1));
    }
}

后话

中间 \(\rm{DP}\) 的过程说人话就是将原序列分成若干个区间, 然后再在每段中选择一个数使用其进行超越和交换操作.

附一个 Hard Ver. 中关键结论的证明

  • 假设存在一个数 \(k\) 满足 \(k > p_1\)\(k < n\),并且我们将 \(a[p_1]\) 移动到 \(k\)。现在考虑 \(a[k+1]\)

    1. 如果 \(a[p_1] + 2 \leq a[k+1]\)
      那么我们应当将 \(a[p_1]\) 进一步移动到 \(k+1\),并重复这一操作,直到找到一个点 \(q\) 满足:

      \[q > p_1 \quad \text{且} \quad q < n \quad \text{且} \quad a[p_1] + 2 > a[q] \]

    2. 如果 \(a[p_1] + 2 > a[q]\)
      这意味着 \(a[q] \leq a[p_1] + 1\)。假设 \(a[q]\) 取最大值 \(a[p_1] + 1\),则:

      • 对于区间 \([p_1 + 1, q)\),贡献为 \(a[q] + 1 = \max(a[q]) + 1 = a[p_1] + 2\)
      • 对于点 \(q\),贡献为 \(a[p_1] + 1\)

      而如果我们将 \(a[p_1]\) 移动到 \(q - 1\),则区间 \([p_1 + 1, q)\) 的贡献仍然是 \(a[p_1] + 2\)。因此,如果存在这样的 \(q\)(即 \(q > p_1\)\(q < n\)),我们不应该将 \(p_1\) 向后移动,而是让它保持在原位(即 \(q = p_1\))。否则,如果找不到这样的 \(q\),则说明我们应该将 \(p_1\) 移动到 \(n\)

    综上,对于每个 \(p_i\),最优策略是:要么保持 \(q_i = p_i\),要么 \(q_i = n\)

posted @ 2025-05-06 16:41  Steven1013  阅读(43)  评论(0)    收藏  举报