【SCOI2010】【单调队列优化DP】股票交易

来源:互联网 发布:db2数据库启停 编辑:程序博客网 时间:2024/05/16 09:11

很明显的DP,不过省选主要考察的就是DP优化

朴素的做法如下:
状态:用f[i][j]表示前i天中,最后1天收盘时手中还持有j股的股票所能得到的最大收益。

转移方程:f[i][j] = max{f[i - 1][j],f[i - W - 1][j - k1] - ap[i] * k1,f[i - W - 1][j + k2] + bp[i] * k2}。
其中,k1 <= as[i], k2 <= bs[i]。

以上算法的复杂度是O(T * maxP ^ 2),显然过不了极限数据。

对于以上转移方程方程,可做如下转化:
令t = i - W - 1,p = j - k1, q = j + k2。
忽略f[i - 1][j]项,则有:
f[i][j] = max{f[t][p] - ap[i] * (j - p),f[t][q] + bp[i] * (q - j)},
且p >= j - as[i], q <= j + bs[i]。
即f[i][j] = max{f[t][p] + ap[i] * p - ap[i] * j,    (1)
                f[t][q] + bp[i] * q - bp[i] * j}。  (2)
这样一来,可以发现(1)式中,f[t][p] + ap[i] * p部分,和(2)式中f[t][q] + bq[i] * q部分只与p, q有关,于是可以使用单调队列优化。(以上转自Whjpji)

代码:

#include<cstdio>#include<cstring>using namespace std;const int maxn = 2000 + 10;struct day{int ap,bp,as,bs;}deal[maxn];int f[maxn][maxn];int q[maxn],val[maxn];int t,maxp,w;int l,r;int ans = 0;void init(){freopen("bzoj1855.in","r",stdin);freopen("bzoj1855.out","w",stdout);}int max(int a,int b){return a > b ? a : b;}void readdata(){scanf("%d%d%d",&t,&maxp,&w);for(int i = 1;i <= t;i++){scanf("%d%d%d%d",&deal[i].ap,&deal[i].bp,&deal[i].as,&deal[i].bs);}}void solve(){memset(f,~0x3f,sizeof(f));f[0][0] = 0;for(int i = 1;i <= t;i++){for(int j = 0;j <= deal[i].as;j++)f[i][j] = -deal[i].ap * j;for(int j = 0;j <= maxp;j++)f[i][j] = max(f[i][j],f[i-1][j]);int t = i - w - 1;if(t >= 0){l = r = 0;for(int j = 0;j <= maxp;j++){while(l < r && q[l] < j - deal[i].as)++l;while(l < r && f[t][j] + j * deal[i].ap >= val[r-1])--r;val[r] = f[t][j] + j * deal[i].ap;q[r++] = j;if(l < r)f[i][j] = max(f[i][j],val[l] - j * deal[i].ap);}l = r = 0;for(int j = maxp;j >= 0;j--){while(l < r && q[l] > j + deal[i].bs)++l;while(l < r && f[t][j] + j * deal[i].bp >= val[r-1])--r;val[r] = f[t][j] + j * deal[i].bp;q[r++] = j;if(l < r)f[i][j] = max(f[i][j],val[l] - j * deal[i].bp);}}ans = max(f[i][0],ans);}printf("%d",ans);}int main(){init();readdata();solve();return 0;}


原创粉丝点击