題解 P5851 [USACO19DEC]Greedy Pie Eaters P
阿新 • • 發佈:2021-08-11
題解 P5851 [USACO19DEC]Greedy Pie Eaters P
應該比較好看出是區間 DP(
n 個派, m 個奶牛
f[l][r][i] 表示第 i 個派尚未被吃時能吃掉它和能吃掉派區間 [l,r] 的奶牛(們)的最大體重
d[l][r] 表示派 [l,r] 全被吃掉後最大的奶牛總體重
對於每一個 f[l][r][i], 派 i 只能是位於區間最左/右邊的(因為要吃就必須把 [l,r] 全吃掉), 於是可得出:
\(f[l][r][i] = max(f[l+1][r][i], f[l][r+1][i]), l <= i <= r\)
分類討論每一個 d[l][r] 的取值情況
- d[l][r] 可以由兩個子區間合併而成
\(d[l][r] = d[l][k] + d[k+1][r], l<=k<r\) - d[l][r] 可以由一塊沒有被吃過的派和剩餘區間組成
\(d[l][r] = f[l][r][k] + d[l][k - 1] + d[k + 1][l],l<=k<=r\)
程式碼如下
( ゚∀゚)o彡゜ ヒーコー ヒーコー!#include <stdio.h> #include <algorithm> int n, m; int f[303][303][303]; int d[303][303]; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= m; i++) { int x, y, z; scanf("%d %d %d", &x, &y, &z); for (int j = y; j <= z; j++) f[y][z][j] = x; } for (int len = 1; len <= n; len++) for (int l = 1; l + len - 1 <= n; l++) { int r = l + len - 1; for (int k = l; k <= r; k++) f[l][r][k] = std:: max(f[l][r][k], f[l][r - 1][k]), f[l][r][k] = std:: max(f[l][r][k], f[l + 1][r][k]); } for (int len = 1; len <= n; len++) for (int l = 1; l + len - 1 <= n; l++) { int r = l + len - 1; // 1. 兩個子區間合併而成 for (int k = l; k < r; k++) d[l][r] = std:: max(d[l][r], d[l][k] + d[k + 1][r]); // 2. 一個未吃過的派 k 與剩餘部分組成 for (int k = l; k <= r; k++) d[l][r] = std:: max(d[l][r], d[l][k - 1] + f[l][r][k] + d[k + 1][r]); } printf("%d\n", d[1][n]); return 0; }