洛谷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;
}