洛谷P2466 [SDOI2008]Sue的小球 題解 區間DP+費用提前計算
阿新 • • 發佈:2020-09-02
題目連結: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; }