解题思路:
很容易想到
dp[now][i]
d
p
[
n
o
w
]
[
i
]
表示第now天拥有i张股票赚的最多的钱,那么转移方程为:
1.不交易:
dp[now][i]=dp[now−1][i]
d
p
[
n
o
w
]
[
i
]
=
d
p
[
n
o
w
−
1
]
[
i
]
2.买进:
dp[now][i]=max(dp[now−w−1][j]−Ap[now]∗(i−j))
d
p
[
n
o
w
]
[
i
]
=
m
a
x
(
d
p
[
n
o
w
−
w
−
1
]
[
j
]
−
A
p
[
n
o
w
]
∗
(
i
−
j
)
)
(i−As[now]≤j≤i)
(
i
−
A
s
[
n
o
w
]
≤
j
≤
i
)
3.卖出:
dp[now][i]=max(dp[now−w−1][j]+Bp[now]∗(j−i))
d
p
[
n
o
w
]
[
i
]
=
m
a
x
(
d
p
[
n
o
w
−
w
−
1
]
[
j
]
+
B
p
[
n
o
w
]
∗
(
j
−
i
)
)
(i≤j≤i+Bs[now])
(
i
≤
j
≤
i
+
B
s
[
n
o
w
]
)
但这样状态是
O(n2)
O
(
n
2
)
,转移是
O(n)
O
(
n
)
,总时间复杂度是
O(n3)
O
(
n
3
)
的。如何优化到
O(n2)
O
(
n
2
)
呢?
其实我们可以利用单调性用单调队列将转移优化到O(1)。
拿买进举例:
dp[now][i]=max(dp[now−w−1][j]−Ap[now]∗(i−j)))
d
p
[
n
o
w
]
[
i
]
=
m
a
x
(
d
p
[
n
o
w
−
w
−
1
]
[
j
]
−
A
p
[
n
o
w
]
∗
(
i
−
j
)
)
)
,
即
max(dp[now−w−1][j]+Ap[now]∗j−Ap[now]∗i)
m
a
x
(
d
p
[
n
o
w
−
w
−
1
]
[
j
]
+
A
p
[
n
o
w
]
∗
j
−
A
p
[
n
o
w
]
∗
i
)
,
注意到转移只与
dp[now−w−1]
d
p
[
n
o
w
−
w
−
1
]
一列有关,且
dp[now−w−1][j]+Ap[now]∗j
d
p
[
n
o
w
−
w
−
1
]
[
j
]
+
A
p
[
n
o
w
]
∗
j
是单增的,而我们又要求最大值,所以就可以用一个单调递减队列维护
dp[now−w−1][j]+Ap[now]∗j
d
p
[
n
o
w
−
w
−
1
]
[
j
]
+
A
p
[
n
o
w
]
∗
j
,决策时取队首就行了。
卖出是一样的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=2005;
const ll INF=1e17;
int n,m,t;
int Ap[N],Bp[N],As[N],Bs[N];
int head,tail,q[N];
ll dp[N][N];
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
n=getint(),m=getint(),t=getint()+1;
for(int i=1;i<=n;i++)
Ap[i]=getint(),Bp[i]=getint(),As[i]=getint(),Bs[i]=getint();
for(int i=0;i<=n;i++)dp[i][0]=0;
for(int now=0;now<=n;now++)
for(int i=1;i<=m;i++)dp[now][i]=-INF;
for(int now=1;now<=t;now++)
for(int i=0;i<=m;i++)
{
dp[now][i]=dp[now-1][i];
if(i<=As[now])dp[now][i]=max(dp[now][i],-1ll*Ap[now]*i);
}
for(int now=t+1;now<=n;now++)
{
for(int i=0;i<=m;i++)dp[now][i]=dp[now-1][i];
memset(q,0,sizeof(q));
head=1,tail=0;
for(int i=0;i<=m;i++)
{
while(head<=tail&&q[head]<i-As[now])head++;
while(head<=tail&&dp[now-t][i]+1ll*Ap[now]*i>dp[now-t][q[tail]]+1ll*Ap[now]*q[tail])tail--;
q[++tail]=i;
dp[now][i]=max(dp[now][i],dp[now-t][q[head]]-1ll*Ap[now]*(i-q[head]));
}
head=1,tail=0;
for(int i=m;i>=0;i--)
{
while(head<=tail&&q[head]>i+Bs[now])head++;
while(head<=tail&&dp[now-t][i]+1ll*Bp[now]*i>dp[now-t][q[tail]]+1ll*Bp[now]*q[tail])tail--;
q[++tail]=i;
dp[now][i]=max(dp[now][i],dp[now-t][q[head]]+1ll*Bp[now]*(q[head]-i));
}
}
ll ans=0;
for(int i=0;i<=m;i++)
ans=max(ans,dp[n][i]);
cout<<ans;
return 0;
}