[BZOJ 1855][SCOI 2010]股票交易(单调队列优化DP)
2015-03-20 11:54
316 查看
题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1855思路
很显然是个DP题,比较容易想到下面的DP做法:用f[i][j]f[i][j]表示第ii天,手上有jj个股票的最大获利。显然最终的答案为max{f[i][0]}max\{f[i][0]\}(显然以某天交易结束后收手不干,肯定是手上没有股票是最优的),DP初始化如下:
f(x)={f[i][j]=max{f[i−1][j],−apj},j<=as(第i天没买或全是这天买的)f[i][j]=f[i−1][j],j>as(手上股票超出了一次购买的限制,只能是第i天没买) f(x)=\left\{
\begin{aligned}
f[i][j]=max\{f[i-1][j],-a_pj\},j<=a_s(第i天没买或全是这天买的) \\
f[i][j]=f[i-1][j],j>a_s (手上股票超出了一次购买的限制,只能是第i天没买)\\
\end{aligned}
\right.
而DP方程则为(以转移情况为购入股票举例)
f[i][j]=max{f[i−w−1][k]+ap(j−k)} f[i][j]=max\{f[i-w-1][k]+a_p(j-k)\}
这样做的正确性是显然的,f[i][j]f[i][j]一定是前ii天里手持jj股的最优解,这样一来我们就节省了一维时间复杂度,但是还是会TLE。
变化一下这个DP方程:
f[i][j]=max{f[i−w−1][k]−apk+apj} f[i][j]=max\{f[i-w-1][k]-a_pk+a_pj\}
一般可以用单调队列优化的DP都能满足形如f[x]=max(min){f[k]}+g[x]f[x]=max(min)\{f[k]\}+g[x]的形式,那么我们可以把这里的f[i−w−1][k]f[i-w-1][k]看作是上面的f[k]f[k],apja_pj看作是上面的g[x]g[x],于是就可以从小到大枚举jj,并用单调队列维护二元组(k,f[i−w−1][k])(k,f[i-w-1][k]),并保证队首的f[i−w−1][k]f[i-w-1][k]是最大的,DP到某个jj时,先把队首所有不合法的f[i−w−1][k]f[i-w-1][k]全部弹出,然后用第一个合法的队首去更新f[i][j]f[i][j],然后将这时的f[i−w−1][j]f[i-w-1][j]放入队尾,并同时维护队列单调性。
而卖出的做法也非常相似,在这里就不再赘述了
代码
刚开始数组开大了,直接卡成TLE。。。郁闷。。。#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #define MAXN 2100 #define INF 0x3f3f3f3f using namespace std; pair<int,int>q[MAXN]; int f[MAXN][MAXN]; int T,maxP,w; int main() { int ans=-INF; memset(f,-INF,sizeof(f)); scanf("%d%d%d",&T,&maxP,&w); for(int i=1;i<=T;i++) { int ap,bp,as,bs; scanf("%d%d%d%d",&ap,&bp,&as,&bs); for(int j=0;j<=as;j++) f[i][j]=-ap*j; //初始化f[i][j]=-ap*j(光买了股票) for(int j=0;j<=maxP;j++) f[i][j]=max(f[i][j],f[i-1][j]); //初始化什么都没买的情况更新f数组 int k=i-w-1; //单调队列里保存的就是(j,f[w][j]+ap[i]*j(-bp[i]*j))这个二元组 if(k>=0) { int h=0,t=0; for(int j=0;j<=maxP;j++) { //买入股票 while(h<t&&q[h].first<j-as) h++; while(h<t&&q[t-1].second<=f[k][j]+ap*j) t--; q[t++]=make_pair(j,f[k][j]+ap*j); if(h<t) f[i][j]=max(f[i][j],q[h].second-ap*j); } h=0,t=0; for(int j=maxP;j>=0;j--) { //卖出股票 while(h<t&&q[h].first>j+bs) h++; //!!!!! while(h<t&&q[t-1].second<=f[k][j]+bp*j) t--; q[t++]=make_pair(j,f[k][j]+bp*j); if(h<t) f[i][j]=max(f[i][j],q[h].second-bp*j); } } ans=max(ans,f[i][0]); //显然以某天交易结束后收手不干,肯定是手上没有股票是最优的 } printf("%d\n",ans); return 0; }
相关文章推荐
- BZOJ1855 [Scoi2010]股票交易 【单调队列优化dp】
- bzoj1855: [Scoi2010]股票交易 单调队列优化dp ||HDU 3401
- 【单调队列优化DP】BZOJ1855-[Scoi2010]股票交易
- [BZOJ1855][Scoi2010]股票交易(DP+单调队列优化)
- BZOJ 1855: [Scoi2010]股票交易:(单调队列优化DP)
- BZOJ 1855 [Scoi2010]股票交易 单调队列优化DP
- 【SCOI2010】【单调队列优化DP】股票交易
- 【BZOJ1855】[Scoi2010]股票交易 DP+单调队列
- 【bzoj1855||hdu3401】股票交易——单调队列优化dp
- BZOJ 1855 股票交易(单调队列优化DP)
- bzoj1855 [Scoi2010]股票交易(dp+单调队列优化)
- 1855: [Scoi2010]股票交易[单调队列优化DP]
- [bzoj1855][Scoi2010]股票交易_动态规划_单调队列
- bzoj1855 SCOI2010 股票交易【单调队列优化dp】
- 股票交易 【SCOI 2010】HDU 3401 (单调队列优化DP入门)
- BZOJ 1915: [Usaco2010 Open]奶牛的跳格子游戏 单调队列优化dp
- [bzoj1293][SCOI2009]生日礼物 单调队列优化dp
- [SCOI2010] 股票交易 (单调队列优化dp)
- BZOJ 1911 [Apio2010]特别行动队(单调队列优化DP)
- SCOI2010——股票交易(单调队列DP)