看到这道题之后设计出的状态是f[i,j]为第i天各种交易之后持有j股票的情况下所能获得的最大利益。
那么转移应该是f[i,j]=f[i',j']+(j'-j)*x[i]
其中i-i'>W,当j'>j时,j'-j<=BS[i],x[i]=BP[i]。当j>j'时,j-j'<=AS[i],x[i]=AP[i]
这样的复杂度是T^2*MaxP^2
我们观察到,对于i和i+1,其决策域基本上是重复的,于是将f[i,j]的状态改为前i天各种交易之后持有j股票的情况下所能获得的最大利益。
这样f[i,j]=max(f[i-1,j],f[i-W-1,j']+(j'-j)*x[i]),但是T*MaxP^2还是要超时
我们把买和卖的决策分开考虑,以便得到进一步的优化
以买入为例,f[i,j]=max(f[i-W-1,j']+(j'-j)*AP[i])=max(f[i-W-1,j']+j'*AP[i])-j*AP[i],符合单调队列优化的模型,优化后的总时间复杂度为T*MaxP
要注意初始化
//By YY_More #include<cstdio> #include<iostream> #include<algorithm> using namespace std; int f[2012][2012],D[2012]; int t,T,MaxP,W,L,R,AP[2012],BP[2012],AS[2012],BS[2012]; void initer(){ fill(&f[0][0],&f[W+1][MaxP]+1,-2100000000); for (int k=1;k<W+2;k++){ for (int j=0;j<=AS[k];j++) f[k][j]=max(-AP[k]*j,f[k-1][j]); for (int j=AS[k]+1;j<=MaxP;j++) f[k][j]=f[k-1][j]; } }; void init(int x){ for (int j=0;j<=MaxP;j++) f[x][j]=f[x-1][j]; }; void buy(int x){ L=0;R=-1; for (int j=0;j<=MaxP;j++){ while (L<=R&&f[x-W-1][D[R]]+D[R]*AP[x]<=f[x-W-1][j]+j*AP[x]) R--; D[++R]=j; while (j-D[L]>AS[x]) L++; f[x][j]=max(f[x][j],f[x-W-1][D[L]]-(j-D[L])*AP[x]); } }; void sell(int x){ L=0;R=-1; for (int j=MaxP;j>=0;j--){ while (L<=R&&f[x-W-1][D[R]]+D[R]*BP[x]<=f[x-W-1][j]+j*BP[x]) R--; D[++R]=j; while (D[L]-j>BS[x]) L++; f[x][j]=max(f[x][j],f[x-W-1][D[L]]+(D[L]-j)*BP[x]); } }; int main(){ scanf("%d",&t); while (t-->0){ scanf("%d%d%d",&T,&MaxP,&W); for (int i=1;i<=T;i++) scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]); initer(); for (int i=W+2;i<=T;i++){ init(i); sell(i); buy(i); } printf("%d\n",f[T][0]); } return 0; }