洛谷P2466 [SDOI2008]Sue的小球 题解 区间DP+费用提前计算

题目链接:https://www.luogu.com.cn/problem/P2466

题目大意:略。

解题思路:

首先将 \(n\) 个彩蛋按照 \(x\) 从小到大排序。

然后定义状态 \(f[L][R][s]\),其含义为:

  • \(s=0\) 时:接完了第 \([L,R]\) 范围内的所有彩蛋,且当前处在最左边的位置(\(L\)处),收获的得分+给未来造成的得分的损耗之和的最大值;
  • \(s=1\) 时:接完了第 \([L,R]\) 范围内的所有彩蛋,且当前处在最右边的位置(\(R\)处),收获的得分+给未来造成的得分的损耗之和的最大值。

则状态转移方程为:

\(L = R\) 时,

\[f[L][R][s] = y_L - |x_0 - x_L| \times \sum_{1 \le i \le n} v_i \]

\(L \lt R\) 时,

\[f[L][R][0] = \max\{f[L+1][R][0] + y_L - (\sum_{i\le L} v_i + \sum_{i \gt R} v_i) \times (x_{L+1} - x_L), f[L+1][R][1] + y_L - (\sum_{i\le L} v_i + \sum_{i \gt R} v_i) \times (x_R - x_L) \} \]

\[f[L][R][1] = \max \{f[L][R-1][0] + y_R - (\sum_{i \lt L} v_i + \sum_{i \ge R} v_i) \times (x_R - x_L) , f[L][R-1][1] + y_R - (\sum_{i \lt L} v_i + \sum_{i \ge R} v_i) \times (x_R - x_{R-1}) \} \]

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
struct Node {
    int x, y, v;
    Node() {};
    Node(int _x, int _y, int _v) { x = _x; y = _y; v = _v; }
} a[maxn];
bool cmp(Node a, Node b) {
    return a.x < b.x;
}
int n, x0;
long long f[maxn][maxn][2], sumv[maxn];
bool vis[maxn][maxn][2];
long long dfs(int L, int R, int s) {
    if (L == R) {
        return a[L].y - abs(x0 - a[L].x) * sumv[n];
    }
    if (vis[L][R][s]) return f[L][R][s];
    vis[L][R][s] = true;
    if (s == 0) {
        long long tmp1 = dfs(L+1, R, 0) + a[L].y - (sumv[L] + sumv[n] - sumv[R]) * (a[L+1].x - a[L].x);
        long long tmp2 = dfs(L+1, R, 1) + a[L].y - (sumv[L] + sumv[n] - sumv[R]) * (a[R].x - a[L].x);
        return f[L][R][0] = max(tmp1, tmp2);
    }
    else {  // s == 1
        long long tmp1 = dfs(L, R-1, 0) + a[R].y - (sumv[L-1] + sumv[n] - sumv[R-1]) * (a[R].x - a[L].x);
        long long tmp2 = dfs(L, R-1, 1) + a[R].y - (sumv[L-1] + sumv[n] - sumv[R-1]) * (a[R].x - a[R-1].x);
        return f[L][R][1] = max(tmp1, tmp2);
    }
}
int main() {
    scanf("%d%d", &n, &x0);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i].x);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i].y);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i].v);
    sort(a+1, a+1+n, cmp);
    for (int i = 1; i <= n; i ++) sumv[i] = sumv[i-1] + a[i].v;
    printf("%.3lf\n", (double) max(dfs(1, n, 0), dfs(1, n, 1))/ 1000.0);
    return 0;
}
posted @ 2020-09-02 20:07  quanjun  阅读(187)  评论(0编辑  收藏  举报