您的位置:首页 > 其它

2017.9.9 股票交易 思考记录

2017-09-09 22:53 232 查看
这题、只要找到了突破口就好做了

首先最好想的是n^3的dp、f【i】【j】表示在第i天有j张票的最大收益、枚举卖出和买入的个数即可

但我们需要一个n^2的做法

所以我们就可以分析题目的特点:

这个题有一个前w天的限制,但w=0时它又与普通dp无异,所以不是突破口,它只是刷一下存在感

然后对于每一天都有收益,,如果把他想成限制,那他就比所有的天都一样要麻烦;

但如果把他想成放宽,则他这一天里,每一张的买入和卖出是一样的

所以我们考虑如何用一天内相同量来简化决策

对于两个可取的决策:  f[j]+(j-i)*v   和  f[k]+(k-i)*v

如果i+1,即到了多一张票数:

             f[j]+(j-i-1)*v   &   f[k]+(k-i-1)*v

他们都只多出了一个1*v

所以这一种票数的决策其实可以沿用上一张票数的情况

所以我们加入合法的、退出不合法的

新加入的比以前加入的晚被弹出

每加入一个新节点就可以删除旧节点

就是单调队列了

码(单调队列不熟、写的极其难看):

#include<iostream>
#include<cstdio>
using namespace std;
int n,sx,w,i,j,f[2002][2002],g1[2002],g2[2002],ans,c,v,sc,sv;
int main()
{
scanf("%d%d%d",&n,&sx,&w);
w++;
for(i=1;i<=sx;i++)
f[0][i]=-1000000009;
for(i=1;i<=n;i++)
{
scanf("%d%d%d%d",&c,&v,&sc,&sv);
for(j=0;j<=sx;j++)
f[i][j]=f[i-1][j];//继承相当于放弃这一天的买卖机会
int z1=1,z2=1,z3=1,z4=1;
g1[1]=1;
int qi=2;
g2[1]=0;
for(j=0;j<=sx;j++)
{
//卖的出队
if(g1[z1]<=j)++z1;//卖的比之后的相等、小就被迫出队
for(;qi<=min(j+sv,sx);qi++)//卖的 加入队列
{
while(z1<=z2&&(f[max(i-w,0)][g1[z2]]+(g1[z2]-j)*v<f[max(i-w,0)][qi]+(qi-j)*v))--z2;
g1[++z2]=qi;
}
if(j!=sx)f[i][j]=max(f[i][j],f[max(i-w,0)][g1[z1]]+(g1[z1]-j)*v);
if(j!=0)
{
if(g2[z3]<j-sc)++z3;//买的出队
if(j!=1){while(z3<=z4&&f[max(i-w,0)][g2[z4]]-(j-g2[z4])*c<f[max(i-w,0)][j-1]-c )z4--;//买的入队
g2[++z4]=j-1;}
f[i][j]=max(f[i][j],f[max(i-w,0)][g2[z3]]-(j-g2[z3])*c);
}
// cout<<f[i][j]<<" ";
}
// cout<<endl;
}
for(i=0;i<=sx;i++)
ans=max(ans,f
[i]);
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: