BZOJ 1855 [Scoi2010]股票交易 ——动态规划
DP方程是比较简单的,主要有三种:什么都不做、买入、卖出。
发现买入卖出都是$\Theta (n^3)$但是转移方程都是线性的,而且决策和当前的情况是分开的。
所以可以单调队列优化。
复杂度$\Theta(n^2)$
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define inf 1044266559 #define ll long long #define mp make_pair int dp[2005][2005]; int que[2005],hd,tl; struct Day{int ap,bp,as,bs;}a[2005]; int n,mxp,w; int main() { scanf("%d%d%d",&n,&mxp,&w); F(i,1,n) scanf("%d%d%d%d",&a[i].ap,&a[i].bp,&a[i].as,&a[i].bs); memset(dp,-0x3f,sizeof dp); dp[0][0]=0; F(i,1,n) { F(j,0,a[i].as) dp[i][j]=max(dp[i][j],-a[i].ap*j); F(j,0,mxp) dp[i][j]=max(dp[i][j],dp[i-1][j]); if (i-w-1>=0){ hd=1,tl=0; F(j,0,mxp) { while (hd<=tl&&que[hd]<j-a[i].as) hd++; while (hd<=tl&&dp[i-w-1][que[tl]]+que[tl]*a[i].ap<=dp[i-w-1][j]+j*a[i].ap) tl--; que[++tl]=j; dp[i][j]=max(dp[i][j],dp[i-w-1][que[hd]]-(j-que[hd])*a[i].ap); } hd=1;tl=0; D(j,mxp,0){ while (hd<=tl&&que[hd]>min(j+a[i].bs,mxp)) hd++; while (hd<=tl&&dp[i-w-1][que[tl]]+que[tl]*a[i].bp<=dp[i-w-1][j]+j*a[i].bp) tl--; que[++tl]=j; dp[i][j]=max(dp[i][j],dp[i-w-1][que[hd]]+(que[hd]-j)*a[i].bp); } } } printf("%d\n",dp[n][0]); }