上午做了两个单调队列简直太机智2333
这个题是说有一神人能预测股票走向,每天已知买进一只股票花的钱ap、抛一只股票挣的钱bp、每天买的数量最大值as、每天卖股票的最大值bs,而且要求任何操作之间都得隔w天,手头的股票最多m股,问你t天之后最多能挣多少钱。就是开始的时候资本是0,欠钱买股票,问最后手里多少钱,你这么神你怎么不自己算→_→
很容易想到转移方程式:对比前一次买进股票dp[i][j]=dp[i-w-1][k]-(j-k)*ap 抛出股票dp[i][j]=dp[i-w-1][k]+(j-k)*bp dp数组表示i天,手头有j支股票时赚的钱,单看这个方程时间复杂度达到三次方,用单调队列优化能降一维,具体操作呢?其实我没懂为啥要这么替换,应该是套路吧。对于抛出股票的行为,设tmp=dp[k][j]+bp*j,维护v[]数组作为单调队列,。j从m遍历到0,每次计算tmp插入单调队列中,这个操作说起来很纠结,也可能是我想错了,欢迎指正,插入队列时j的意义在于将上一次的值插入,然后取队首元素作为最大值,等到dp的递推就是求得当前的最大值,然后因为是卖出去,所以遍历是从大到小,我们设的v[]与实际的dp[]数组相差-bp*j,我们维护单调队列的意义在于每次及时找到当前的最大值嘛,递推dp的时候把差的加上就好啦。还有就是控制一次性抛出的最大值:这个时候j的意义就变成是当前值了,当前的股票数量-队首元素的股票数量若大于bs,一直出队列。应该是说明白了QAQ
/*******************
hdu3401
2016.2.23
202MS 17436K 1621 B C++
*******************/
#include
#include
#include
using namespace std;
int t,n,maxp,w,ap,bp,as,bs,dp[2004][2004],v[2004],q[2004],l,r;
int max(int a,int b) {return a>b?a:b;}
int main()
{
// freopen("cin.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&maxp,&w);
for(int i=1;i<=w+1;i++)
{
scanf("%d%d%d%d",&ap,&bp,&as,&bs);
for(int j=0;j<=maxp;j++)
{
if(j<=as)dp[i][j]=-j*ap;
else dp[i][j]=-1e9;
if(i>1) dp[i][j]=max(dp[i-1][j],dp[i][j]);
}
}
for(int i=w+2;i<=n;i++)
{
scanf("%d%d%d%d",&ap,&bp,&as,&bs);
int k=i-w-1;
l=0,r=-1;//buy
for(int j=0;j<=maxp;j++)
{
int tmp=dp[k][j]-ap*(maxp-j);//dp下标咋还能写错
while(l<=r&&v[r]as) l++;//除去的是差值不满足条件的,天数条件已经控制
dp[i][j]=max(dp[i-1][j],v[l]+ap*(maxp-j));
}
//sell
l=0,r=-1;
for(int j=maxp;j>=0;j--)
{
int tmp=dp[k][j]+bp*j;
while(l<=r&&v[r]bs) l++;
dp[i][j]=max(dp[i][j],v[l]-bp*j);
}
}
printf("%d\n",dp[n][0]);
}
return 0;
}