显然的dp题。
$$f[i][j]:\text{考虑前i天,且有j只股票的最大收益}$$
先考虑卖出的转移:$$f[i][j]=\max_{x\le i-w-1,j\le k\le j+BS_i}\{f[x][k]+(k-j)\times BP_i\}$$
唔,直接按这玩意dp的时间复杂度。。。
优化1:考虑到$x$的取值是单调递增的,用变量维护法:
假设当前考虑到第$i$天,那么$x$就可以取$[1,i-w-1]$中的任何值。
让$$pre[j]=\max_{1\le x \le i-w-1}{f[x][j]}$$
则有$$f[i][j]=\max_{j\le k\le j+BS_i}\{pre[k]+(k-j)\times BP_i\}$$
嗯,这样子的时间复杂度就是$O(np^2)$了,虽然还是会TLE。
$k$的取值是关于$j$的一次函数,试试单调队列优化?把式子变成
$$f[i][j]=-j\times BP_i+\max_{j\le k\le j+BS_i}\{pre[k]+k\times BP_i\}$$
果然可以单调队列优化,时间复杂度$O(np)$啥?NP?
买入的同理:$$f[i][j]=-j\times AP_i
+\max_{j-AS_i\le k<j}\{pre[k]+k\times AP_i\}$$
/**********/省略快读
#define MAXN 2011
#define MAXP 2011
ll f[MAXN][MAXP],pre[MAXP];
ll q[MAXP],h,t;
ll value(ll k,ll w)
{
return pre[k]+k*w;
}
int main()
{
ll n=read(),p=read(),w=read();
memset(f,0xcf,sizeof f);
memset(pre,0xcf,sizeof pre);
pre[0]=0;
for(ll i=1;i<=n;++i)
{
ll AP=read(),BP=read(),AS=read(),BS=read();
if(i>w+1)//维护pre
{
for(ll j=0;j<=p;++j)umax(pre[j],f[i-w-1][j]);
}
h=t=1;
for(ll j=0;j<=p;++j)//买入
{
while(h<t&&q[h]<j-AS)++h;
if(h<t)umax(f[i][j],-j*AP+value(q[h],AP));
while(h<t&&value(q[t-1],AP)<=value(j,AP))--t;
q[t++]=j;
}
h=t=1;
for(ll j=p;j>=0;--j)//卖出
{
while(h<t&&q[h]>j+BS)++h;
if(h<t)umax(f[i][j],-j*BP+value(q[h],BP));
while(h<t&&value(q[t-1],BP)<=value(j,BP))--t;
q[t++]=j;
}
for(ll j=0;j<=p;++j)umax(f[i][j],f[i-1][j]);//注意可以直接继承前一天
}
ll ans=0;
for(ll j=0;j<=p;++j)umax(ans,f[n][j]);
printf("%lld",ans);
return 0;
}
%%%
问个问题 qwq 啥叫$k$的取值是关于$j$的一次函数 没理解为啥qwq
$k$的上下界都是关于$j$的一次函数
umax 是啥?
checkmax
#细!