标签:style blog class code c int
题意:让你炒股票,每天都有买进的额度和价格以及卖出的额度和价格,并规定时间和最多的持有股票是多少,而且买卖操作要隔w+1天求最高的利润
思路:显然分三种情况:不买不卖,买,卖,设dp[i][j]表示第i天持有j股票的最高利润
如果不买不卖的话就是:dp[i][j]=dp[i-1][j]
买: dp[i][j]=max(dp[i][j],dp[pre][k]-(j-k)*ap[i])
卖: dp[i][i]=max(dp[i][j],dp[pre][k]+(k-j)*bp[i])
拿买来说的话:dp[pre][k]-(j-k)*ap[i]=dp[pre][k]-j*ap[i]+k*ap[i],我们的目的是尽量大,所以我们尽量找一个最大的利润,那么维持一个单调队列就是了,重点是队尾的操作,如果后一个比前一个利润高的话,就移动,这样就可以后面的操作数是最优的
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int MAXN = 2010; const int INF = 0x3f3f3f3f; typedef pair<int, int> pii; int Time,maxp,w; int ap[MAXN],bp[MAXN],as[MAXN],bs[MAXN]; int dp[MAXN][MAXN]; pii que[MAXN]; int st,ed; int main(){ int t; scanf("%d", &t); while (t--){ memset(dp[0],-INF,sizeof(dp[0])); dp[0][0] = 0; scanf("%d%d%d", &Time, &maxp, &w); for (int i = 1; i <= Time; i++) scanf("%d%d%d%d", &ap[i], &bp[i], &as[i], &bs[i]); int ans = 0; for (int i = 1; i <= Time; i++){ memcpy(dp[i], dp[i-1], sizeof(dp[i])); if (i <= w+1){ for (int j = 0; j <= as[i]; j++) dp[i][j] = max(dp[i-1][j], -ap[i]*j); continue; } st = ed = 0; int pre = i-w-1; for (int j = 0; j <= maxp; j++){ pii elem = pii(dp[pre][j]+j*ap[i],j); que[ed++] = elem; while (ed-st >= 1 && que[st].second < j-as[i]) st++; while (ed-st >= 2 && que[ed-1].first >= que[ed-2].first) que[ed-2] = que[ed-1],ed--; dp[i][j] = max(dp[i][j], que[st].first-j*ap[i]); ans = max(ans, dp[i][j]); } st = ed = 0; for (int j = maxp; j >= 0; j--){ pii elem = pii(dp[pre][j]+j*bp[i], j); que[ed++] = elem; while (ed-st >= 1 && que[st].second > j+bs[i]) st++; while (ed-st >= 2 && que[ed-1].first >= que[ed-2].first) que[ed-2] = que[ed-1],ed--; dp[i][j] = max(dp[i][j], que[st].first-j*bp[i]); ans = max(ans, dp[i][j]); } } printf("%d\n", ans); } return 0; }
HDU - 3401 Trade,布布扣,bubuko.com
标签:style blog class code c int
原文地址:http://blog.csdn.net/u011345136/article/details/25537271