题意
最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgww预测到了未来 天内某只股票的走势,第 天的股票买入价为每股 ,第 天的股票卖出价为每股 (数据保证对于每个 ,都有 ),但是每天不能无限制地交易,于是股票交易所规定第 天的一次买入至多只能购买 股,一次卖出至多只能卖出 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 天,也就是说如果在第 天发生了交易,那么从第 天到第 天,均不能发生交易。
同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 。
在第 天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然, 天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
分析
dp状态并不难想,以 前 天 作为 阶段,以 第 天结束时持有 股 为 状态,可得:
:表示第
天结束时持有
股的最大总收益
共有
种状态转移的情况:
- 第 天不进行任何交易;
- 第 天买入 股,由于交易需间隔 天,故对应 ,因为 ,所以 ;
- 第 天卖出 股,由于交易需间隔 天,故对应 ,因为 ,所以 ;
状态转移方程:
初值:
,其余均为
;
目标:
;
直接采用三重循环的时间复杂度会达到 ,故需要对其进行优化,显然状态转移方程的②式和③式满足单调队列优化的条件 (1D/1D动态规划优化),当固定阶段 时,有:
- 决策 的上下边界是关于状态 的一次函数;
- 除 外的冗余部分是关于 和 的一次函数
以②式为例,
可转化为: ,其中 ;
对于 任意 ,第一部分的值是相等的,最优决策 只需要满足在范围内即可,故只需要维护 一个 递减, 的单调队列 即可。
对③式做相同处理即可,注意处理下标越界情况,最后总的时间复杂度度为
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int maxn=2e3+10;
int T,MaxP,W;
int AP[maxn],BP[maxn],AS[maxn],BS[maxn];
int F[maxn][maxn];
int GA(int i,int k)
{
return F[max(0,i-W-1)][k]+k*AP[i];
}
int GB(int i,int k)
{
return F[max(0,i-W-1)][k]+k*BP[i];
}
int main()
{
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]);
memset(F,0xcf,sizeof(F));
F[0][0]=0;
for(int i=1;i<=T;i++)
{
//第i天不交易
for(int j=0;j<=MaxP;j++)
F[i][j]=F[i-1][j];
//第i天买入j-k股
deque<int> q;
for(int j=0;j<=MaxP;j++)
{
while(!q.empty()&&q.front()<j-AS[i]) //保证下界j-AS[i]
q.pop_front();
if(!q.empty())
F[i][j]=max(F[i][j],GA(i,q.front())-j*AP[i]);
while(!q.empty()&&GA(i,q.back())<=GA(i,j))
q.pop_back();
q.push_back(j); //新加入的k一定小于j,保证了上界j
}
//第i天卖出k-j股
q.clear();
for(int k=1;k<=min(MaxP,BS[i]);k++)
{
while(!q.empty()&&GB(i,q.back())<=GB(i,k))
q.pop_back();
q.push_back(k);
}
for(int j=0;j<=MaxP;j++)
{
while(!q.empty()&&q.front()<=j) //保证下界j
q.pop_front();
if(!q.empty())
F[i][j]=max(F[i][j],GB(i,q.front())-j*BP[i]);
if(j+BS[i]+1<=MaxP)
{
while(!q.empty()&&GB(i,q.back())<=GB(i,j+BS[i]+1))
q.pop_back();
q.push_back(j+BS[i]+1); //新加入的k一定小于等于j+BS[i],保证了上界j+BS[i]
}
}
}
int ans=0;
for(int j=0;j<=MaxP;j++)
ans=max(ans,F[T][j]);
printf("%d\n",ans);
return 0;
}