题意:
给出未来T天股票的买进、卖出的价格的最大上限问如何获利最大。
题解:
不买不卖 买 卖
dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] } .....(1)
x<i-w, 0<j-y<MaxP x<i-w, 0<y-j<MaxP
令pre=i-w-1;
==> dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2)
为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的
这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较
过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是
多余的。由此得出式子(2)的结论。
==> 以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i]; ......(3)
==> 那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。
/**
不买不卖 买 卖
dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] } .....(1)
x<i-w, 0<j-y<MaxP x<i-w, 0<y-j<MaxP
令pre=i-w-1;
==> dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2)
为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的
这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较
过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是
多余的。由此得出式子(2)的结论。
==> 以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i]; ......(3)
==> 那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。
*/
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef __int64 lld;
#define oo 0x3f3f3f3f
#define maxn 2005
int dp[maxn][maxn];
struct NODE
{
int p,s;
}q[maxn];
int APi[maxn],ASi[maxn];
int BPi[maxn],BSi[maxn];
int main()
{
int W,MaxP,T,t,head,tail;
NODE temp;
scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&T,&MaxP,&W);
for(int i=1;i<=T;i++)
scanf("%d %d %d %d",&APi[i],&BPi[i],&ASi[i],&BSi[i]);
memset(dp,-0x3f,sizeof dp);
for(int i=1;i<=W+1;i++)
for(int j=0;j<=ASi[i];j++)
dp[i][j]=-APi[i]*j;
for(int i=2;i<=T;i++)
{
for(int j=0;j<=MaxP;j++)
dp[i][j]=max(dp[i][j],dp[i-1][j]);
int pre=i-W-1;
if(pre<=0) continue;
head=tail=0;
for(int j=0;j<=MaxP;j++)
{
temp.p=dp[pre][j]+j*APi[i];
temp.s=j;
//保证队头出来的是最优,那么如果这个temp比队尾还优,那么队尾应该删除
while(head<tail&&q[tail-1].p<temp.p) tail--;
q[tail++]=temp;
while(head<tail&&j-q[head].s>ASi[i]) head++;
dp[i][j]=max(dp[i][j],q[head].p-j*APi[i]);
}
head=tail=0;
for(int j=MaxP;j>=0;j--)
{
temp.p=dp[pre][j]+j*BPi[i];
temp.s=j;
while(head<tail&&q[tail-1].p<temp.p) tail--;
q[tail++]=temp;
while(head<tail&&q[head].s-j>BSi[i]) head++;
dp[i][j]=max(dp[i][j],q[head].p-j*BPi[i]);
}
}
int ans=0;
for(int i=0;i<=MaxP;i++)
ans=max(ans,dp[T][i]);
printf("%d\n",ans);
}
return 0;
}