Codeforces Round #691 (Div. 2) D - Glass Half Spilled(DP)
阿新 • • 發佈:2020-12-20
補下因實驗漏掉的CF(還以為是晚上,沒想到是下午開始)。前三題過的很順利,到D題時想了會發現資料很小爆搜貌似能過,就以為是道水題,交了一發T了,胡亂加了點剪枝還是T。逐漸意識到事情的嚴重性。考慮DP,設 \(dp[i][t][p]\)為在前 \(i\)個玻璃杯中選擇 \(t\)個玻璃杯時容量為 \(p\)的所能獲得的最大水量, 轉移方程是 \(dp[i][t][p]=max(dp[i-1][t][p]+b[i]/2.0, dp[i-1][t-1][p-a[i]]+b[i])\),最後輸出時取 \(max(min(p,dp[n][k][p]))\),本以為能過,交了一發 \(MLE\),當場懵逼。算了下空間發現大概用了 \(2e8\)
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int N = 105; int n, m; int sum, sum_b; int dp[N][N][N * N]; pair<int, int> pa[N]; int main(){ scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d%d", &pa[i].first, &pa[i].second), sum += pa[i].first, sum_b += pa[i].second; for(int i = 0; i <= n; ++i) for(int t = 0; t <= n; ++t) for(int p = 0; p <= sum; ++p) dp[i][t][p] = -1e9; dp[0][0][0] = 0; for(int i = 1; i <= n; ++i) for(int t = 0; t <= i; ++t) for(int p = 0; p <= sum; ++p){ dp[i][t][p] = dp[i - 1][t][p]; if(p >= pa[i].first && t > 0) dp[i][t][p] = max(dp[i][t][p], dp[i - 1][t - 1][p - pa[i].first] + pa[i].second); } for(int i = 1; i <= n; ++i){ double ans = 0; for(int t = 1; t <= sum; ++t){ ans = max(ans, min(1.0 * t, dp[n][i][t] / 2.0 + sum_b / 2.0)); } printf("%.9lf ", ans); } return 0; }