HDU 3401
最近遇到不少DP优化的题,感觉这方面还有些欠缺,现在就多做点这方面的题,练练手。
这题是道较为经典的单调队列优化的题,总共有三种状态,买,卖及其他。
对于买:dp[i][j] = max(dp[i][j],dp[x][y] - (j-y)*sell) (y<=j && y+买的限制>=j && 0 <= x <= i-w-1)
对于卖:dp[i][j] = max(dp[i][j],dp[x][y] + (y-j)*buy) (y >= j && j + 卖的限制 >= y && 0 <= x <= i-w-1)。
优化主要在T,和MAXP上。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<deque> 6 #define MAXN 2012 7 #define INF -(1<<29) 8 using namespace std; 9 int dp[MAXN][MAXN]; 10 int b_price[MAXN]; 11 int s_price[MAXN]; 12 int b_stock[MAXN]; 13 int s_stock[MAXN]; 14 15 void get_dp(int n, int w, int p) 16 { 17 int ans = INF; 18 dp[0][0] = 0; 19 int b[MAXN]; 20 int s[MAXN]; 21 for (int i(0); i<n; ++i) { 22 int b_h(-1),b_e(-1),s_h(-1),s_e(-1); 23 for (int j(0),k(0); j<=p; ++j) { 24 if (i <= w && j <= b_stock[i])dp[i][j] = max(dp[i][j],-b_price[i]*j); 25 if (i != 0)dp[i][j] = max(dp[i][j],dp[i-1][j]); 26 if (i > w) { 27 while (b_h != b_e && b[b_h+1] + b_stock[i] < j) ++b_h; 28 while (s_h != s_e && s[s_h+1] < j) ++s_h; 29 30 while (b_h != b_e && dp[i-w-1][b[b_e]] - b_price[i]*(j-b[b_e]) < dp[i-w-1][j])--b_e; 31 b[++b_e] = j; 32 dp[i][j] = max(dp[i][j],dp[i-w-1][b[b_h+1]]-b_price[i]*(j-b[b_h+1])); 33 while (j + s_stock[i] >= k && k <= p) { 34 while (s_h != s_e && dp[i-w-1][s[s_e]] + s_price[i]*(s[s_e]-j) < dp[i-w-1][k] + s_price[i]*(k-j))--s_e; 35 s[++s_e] = k; 36 ++k; 37 } 38 dp[i][j] = max(dp[i][j],dp[i-w-1][s[s_h+1]]+s_price[i]*(s[s_h+1]-j)); 39 } 40 ans = max(ans,dp[i][j]); 41 } 42 } 43 cout<<ans<<endl; 44 } 45 46 int main() 47 { 48 int t; 49 scanf("%d",&t); 50 while (t--) { 51 for (int i(0); i<MAXN; ++i) { 52 for (int j(0); j<MAXN; ++j) { 53 dp[i][j] = INF; 54 } 55 } 56 int n,w,p; 57 scanf("%d%d%d",&n,&p,&w); 58 for (int i(0); i<n; ++i) { 59 scanf("%d%d%d%d",&b_price[i],&s_price[i],&b_stock[i],&s_stock[i]); 60 } 61 get_dp(n,w,p); 62 } 63 return 0; 64 }