题目描述:
赚大钱钱
题目分析:
很明显是个DP,先设计状态.
DP[i][j]为第i天手里有j张股票能赚到的最多的钱.
初始化
DP[i][j]=−ap[i]∗j
D
P
[
i
]
[
j
]
=
−
a
p
[
i
]
∗
j
转移:
1:DP[i][j]=max(DP[i][j],DP[i−1][j]
1
:
D
P
[
i
]
[
j
]
=
m
a
x
(
D
P
[
i
]
[
j
]
,
D
P
[
i
−
1
]
[
j
]
//选择不买不卖
2:DP[[i][j]=max(DP[i−w−1][k]−ap[i]∗(j−k))(j−as[i]<=k<=j−1)
2
:
D
P
[
[
i
]
[
j
]
=
m
a
x
(
D
P
[
i
−
w
−
1
]
[
k
]
−
a
p
[
i
]
∗
(
j
−
k
)
)
(
j
−
a
s
[
i
]
<=
k
<=
j
−
1
)
//买入
3:DP[i][j]=max(DP[i−w−1][k]+bp[i]∗(k−j))(j+1<=k<=j+bs[i])
3
:
D
P
[
i
]
[
j
]
=
m
a
x
(
D
P
[
i
−
w
−
1
]
[
k
]
+
b
p
[
i
]
∗
(
k
−
j
)
)
(
j
+
1
<=
k
<=
j
+
b
s
[
i
]
)
//卖出
转移
O(N∗Maxp2)
O
(
N
∗
M
a
x
p
2
)
T成SB了
考虑如何优化
我们把上面的 2 3 式子改写一下
买入:f[i][j]=max(f[i−w−1][k]+k∗ap[i])−ap[i]∗j
买
入
:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
w
−
1
]
[
k
]
+
k
∗
a
p
[
i
]
)
−
a
p
[
i
]
∗
j
卖出:f[i][j]=max(f[i−w−1][k]+k∗bp[i])−bp[i]∗j
卖
出
:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
w
−
1
]
[
k
]
+
k
∗
b
p
[
i
]
)
−
b
p
[
i
]
∗
j
括号里面的式子 我们是可以通过维护一个单调递减的队列来O(1)进行取最优值的
优化掉了一层的Maxp
转移
O(N∗Maxp)
O
(
N
∗
M
a
x
p
)
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#include <cstring>
int dp[2001][2001];
int n,w,maxp,ap[2001],bp[2001],as[2001],bs[2001];
int dl[3000];
int main()
{
scanf("%d%d%d",&n,&maxp,&w);
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
memset(dp,128,sizeof(dp));
for(int i=1;i<=n;i++) dp[i][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=as[i];j++) dp[i][j]=-ap[i]*j;
for(int j=0;j<=maxp;j++) dp[i][j]=std::max(dp[i][j],dp[i-1][j]);
if(i-w-1>0)
{
int head=1,tail=0;
for(int j=0;j<=maxp;j++)
{
while(head<=tail&&dl[head]<j-as[i]) head++;//股票购买上限
while(head<=tail&&dp[i-w-1][j]+ap[i]*j>=dp[i-w-1][dl[tail]]+ap[i]*dl[tail]) tail--;
dl[++tail]=j;
dp[i][j]=std::max(dp[i][j],dp[i-w-1][dl[head]]-ap[i]*(j-dl[head]));
}
head=1,tail=0;
for(int j=maxp;~j;j--)
{
while(head<=tail&&dl[head]>j+bs[i]) head++;//股票抛售上限
while(head<=tail&&dp[i-w-1][j]+bp[i]*j>=dp[i-w-1][dl[tail]]+bp[i]*dl[tail]) tail--;
dl[++tail]=j;
dp[i][j]=std::max(dp[i][j],dp[i-w-1][dl[head]]+bp[i]*(dl[head]-j));
}
}
}
int ans=0;
for(int i=0;i<=maxp;i++) ans=std::max(ans,dp[n][i]);
printf("%d\n",ans);
return 0;
}