题目链接: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| imes sum_{1 le i le n} v_i
]
当 (L lt R) 时,
[f[L][R][0] = max{f[L+1][R][0] + y_L - (sum_{ile L} v_i + sum_{i gt R} v_i) imes (x_{L+1} - x_L), f[L+1][R][1] + y_L - (sum_{ile L} v_i + sum_{i gt R} v_i) imes (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) imes (x_R - x_L) , f[L][R-1][1] + y_R - (sum_{i lt L} v_i + sum_{i ge R} v_i) imes (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
", (double) max(dfs(1, n, 0), dfs(1, n, 1))/ 1000.0);
return 0;
}