算是一道比较明显的区间$dp$,但是状态不同往常。
$dp[0/1][i][j]$为拿完第$i$个和第$j$个范围内的所有球后停在左边/右边的最小亏损。
$dp[0][i][j] = min(dp[0][i][j], min(dp[0][i + 1][j] +亏损, dp[1][i + 1][j] + 亏损))$
$dp[1][i][j] = min(dp[1][i][j], min(dp[1][i][j - 1] + 亏损, dp[0][i][j - 1] +亏损))$
亏损的计算方式为速度的区间和*距离
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1000 + 10; 5 struct node { 6 int x, y, v; 7 }a[maxn]; 8 bool cmp(node a, node b) { 9 return a.x < b.x; 10 } 11 int dp[2][maxn][maxn], c[maxn]; 12 int qi(int l, int r) { 13 return c[r] - c[l - 1]; 14 } 15 int main() { 16 int n, q; 17 int sum = 0; 18 memset(dp, 0x3f, sizeof(dp)); 19 scanf("%d%d", &n, &q); 20 for (int i = 1; i <= n; i++) 21 scanf("%d", &a[i].x); 22 for (int i = 1; i <= n; i++) 23 scanf("%d", &a[i].y), sum += a[i].y; 24 for (int i = 1; i <= n; i++) 25 scanf("%d", &a[i].v); 26 a[++n] = { q,0,0 }; 27 sort(a + 1, a + 1 + n, cmp); 28 for (int i = 1; i <= n; i++) 29 c[i] = c[i - 1] + a[i].v; 30 for (int i = 1; i <= n; i++) 31 if (a[i].x == q && a[i].v == 0) 32 dp[0][i][i] = dp[1][i][i] = 0; 33 for (int k = 2; k <= n; k++) { 34 for (int i = 1; i + k - 1 <= n; i++) { 35 int j = i + k - 1; 36 dp[0][i][j] = min(dp[0][i][j], min(dp[0][i + 1][j] + (qi(1, i) + qi(j + 1, n)) * (a[i + 1].x - a[i].x), dp[1][i + 1][j] + (qi(1, i) + qi(j + 1, n)) * (a[j].x - a[i].x))); 37 dp[1][i][j] = min(dp[1][i][j], min(dp[1][i][j - 1] + (qi(1, i - 1) + qi(j, n)) * (a[j].x - a[j - 1].x), dp[0][i][j - 1] + (qi(1, i - 1) + qi(j, n)) * (a[j].x - a[i].x))); 38 } 39 } 40 printf("%.3f ", (sum - min(dp[0][1][n], dp[1][1][n])) / 1000.0); 41 }