[USACO10DEC] Treasure Chest
阿新 • • 發佈:2018-12-09
題目連結
90 Points:智障的區間 DP……設 dp[i][j] 表示區間 [i, j] 能取的最大價值,但我還是 sd 地開了第三維表示先取還是後取的價值。
交上去以為能 A,結果 #2 開心地 MLE……一看記憶體,64MB(把評測機吊起來打一頓)……
100 Points:有些神仙……區間 DP 的滾動陣列,dp[i] 表示以 i 為首的區間得到的最大價值。
換一種思路,定義 dp[l][r] 為在區間 [l,r] 先手的人能取到的最大值,區間的長度每加 1,先手就會互換一次,為了讓這一次的先手更大,就要讓上一次更小,於是得到:
斜著滾掉一維……dp[i] 為從 i 到 i + l - 2 區間最優解:
放上程式碼。
90 分:
#include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 5000 + 10; int n, c[maxn], dp[maxn][maxn][2]; int main(int argc, const char *argv[]) { freopen("..\\nanjolno.in", "r", stdin); freopen("..\\nanjolno.out", "w", stdout); scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &c[i]), dp[i][i][0] = c[i]; for(int i = 1; i < n; ++i) dp[i][i + 1][0] = max(c[i], c[i + 1]), dp[i][i + 1][1] = min(c[i], c[i + 1]); for(int i = 3; i <= n; ++i) { for(int l = 1; l <= n - i + 1; ++l) { int r = l + i - 1; if( c[l] + dp[l + 1][r][1] > c[r] + dp[l][r - 1][1] ) dp[l][r][0] = c[l] + dp[l + 1][r][1], dp[l][r][1] = dp[l + 1][r][0]; else dp[l][r][0] = c[r] + dp[l][r - 1][1], dp[l][r][1] = dp[l][r - 1][0]; } } printf("%d %d\n", dp[1][n][0], dp[1][n][1]); fclose(stdin), fclose(stdout); return 0; }
100 分:
#include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 5000 + 10; int n, c[maxn], dp[maxn]; int main(int argc, const char *argv[]) { freopen("..\\nanjolno.in", "r", stdin); freopen("..\\nanjolno.out", "w", stdout); scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &dp[i]), c[i] = c[i - 1] + dp[i]; for(int i = 2; i <= n; ++i) { for(int l = 1; l <= n - i + 1; ++l) { int r = l + i - 1; dp[l] = c[r] - c[l - 1] - min(dp[l], dp[l + 1]); } } printf("%d\n", dp[1]); fclose(stdin), fclose(stdout); return 0; }