[ABC320F] Fuel Round Trip 题解

题意

在坐标轴上给定 \(N\) 个点,坐标依次为 \(X_1, X_2, \cdots, X_N\),你需要从原点前往 \(X_N\) 并折返,其中在第 \(1\) 个到第 \(N - 1\) 个点上有加油站,其中第 \(i\) 个加油站可以花费 \(P_i\) 购买 \(F_i\) 升汽油,汽油持有上限为 \(H\) 升,每行驶一单位距离需要花费一升汽油。在全部过程中每个加油站至多使用一次,判断是否可以完成行程并输出最小花费。

\(1 \le N, H \le 300\))。

题解

考虑 \(\tt{DP}\),考虑将反向行驶(\(0 \leftarrow X_N\))的过程视为正向行驶(\(0 \rightarrow X_N\)),那么问题转化为了进行两次正向行驶(\(0 \rightarrow X_N\))的行程且不能使用同一个加油站的最小花费,设 \(f_{i, j, k}\) 代表行驶到第 \(i\) 个加油站,两次行程分别还持有 \(j\) 升油和 \(k\) 升油的最小花费。

转移是显然的,考虑是否加油,为哪次行程加油即可,有转移

\[\begin{aligned} f_{i + 1, j, k} &\leftarrow f_{i, j, k} \\ f_{i + 1, \min\left\{j + F_i, H\right\}, k} &\leftarrow f_{i, j, k} + P_i \\ f_{i + 1, j, \min\left\{k + F_i, H\right\}} &\leftarrow f_{i, j, k} + P_i \\ \end{aligned}\]

转移是 \(\mathcal{O}(NH^2)\) 的,下面我们考虑合并答案。

我们设在第一次行程到达 \(X_N\) 后油箱的剩余油量为 \(x\),那么这也就意味着我们的第二次行程开始的起始油量只有 \(x\),但是由于在转移中我们是正向考虑的,即从 \(0\) 以满邮箱开始转移,那么我们考虑转化起始油量的限制。我们发现,若没有第一次行程的干扰,第二次行程可以视为从满油开始,若第一次行程后邮箱剩余油量为 \(x\),这也就意味着在第二次行程开始时有 \(H - x\) 升油被扣除无法使用,从正向来说就是从 \(0\) 以满油开始,到达后需剩余 \(H - x\) 升油以备扣除。那么我们有答案的表达式

\[Ans = \max\limits_{0 \le i \le H, H - i \le j \le H} f_{N, i, j} \]

合并答案的复杂度是 \(\mathcal{O}(H^2)\) 的,总复杂度 \(\mathcal{O}(NH^2)\),可以通过本题。

Code

#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType N, H;

    std::cin >> N >> H;

    ValueVector X(N + 1, 0), F(N + 1, 0), P(N + 1, 0);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> X[i];

    for (valueType i = 1; i < N; ++i)
        std::cin >> P[i] >> F[i];

    constexpr valueType MAX = std::numeric_limits<valueType>::max() >> 2;

    ValueCube DP(N + 1, ValueMatrix(H + 1, ValueVector(H + 1, MAX)));

    DP[0][H][H] = 0;

    for (valueType i = 0; i < N; ++i) {
        for (valueType a = 0; a <= H; ++a) {
            for (valueType b = 0; b <= H; ++b) {
                valueType const dist = X[i + 1] - X[i];

                if (a >= dist && b >= dist)
                    DP[i + 1][a - dist][b - dist] = std::min(DP[i + 1][a - dist][b - dist], DP[i][a][b]);

                if (std::min(a + F[i], H) >= dist && b >= dist)
                    DP[i + 1][std::min(a + F[i], H) - dist][b - dist] = std::min(DP[i + 1][std::min(a + F[i], H) - dist][b - dist], DP[i][a][b] + P[i]);

                if (a >= dist && std::min(b + F[i], H) >= dist)
                    DP[i + 1][a - dist][std::min(b + F[i], H) - dist] = std::min(DP[i + 1][a - dist][std::min(b + F[i], H) - dist], DP[i][a][b] + P[i]);
            }
        }
    }

    valueType ans = MAX;

    for (valueType i = 0; i <= H; ++i)
        for (valueType j = 0; j <= H; ++j)
            if (j >= H - i)
                ans = std::min(ans, DP[N][i][j]);

    if (ans == MAX)
        ans = -1;

    std::cout << ans << std::endl;

    return 0;
}
posted @ 2023-09-17 08:30  User-Unauthorized  阅读(41)  评论(0编辑  收藏  举报