hdu 3401(单调队列优化dp)

来源:互联网 发布:手机能做淘宝链接 编辑:程序博客网 时间:2024/05/29 08:50

传送门
题解:
构造状态dp[i][j]表示第i 天拥有 j只股票的时候,赚了多少钱
从前一天不买不卖 dp[i][j]=max(dp[i-1][j],dp[i][j])
从前i-W-1天买进一些股 dp[i][j]=max(dp[i-W-1][k]-(j-k)*AP[i],dp[i][j])
从i-W-1天卖掉一些股 dp[i][j]=max(dp[i-W-1][k]+(k-j)*BP[i],dp[i][j])
为什么只考虑第i-W-1天的买入卖出情况即可。想想看,i-W-2天是不是可以通过不买不卖将自己的最优状态转移到第i-W-1天?以此类推,之前的都不需要考虑了,只考虑都i-W-1天的情况即可。
对买入股票的情况进行分析,转化成适合单调队列优化的方程形式
dp[i][j]=max(dp[i-W-1][k]+k*AP[i])-j*AP[i]。令f[i-W-1][k]=dp[i-W-1][k]+k*AP[i],则dp[i][j]=max(f[i-W-1][k]) - j*AP[i]。

P.S.1~w+1天不能更新。还有,dp转移时一定要加一句if,否则会出现不合法转移(比如卖股票时q[t] - j < 0)

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int MAXN=2004;int n,m,w,dp[MAXN][MAXN];int ap[MAXN],as[MAXN],bp[MAXN],bs[MAXN];int q[MAXN],h,t;inline int read() {    int x=0,f=1;char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();    return x*f;}int main() {//  freopen("hdu 3401.in","r",stdin);    int kase=read();    while (kase--) {        n=read(),m=read(),w=read();        for (int i=1;i<=n;++i) ap[i]=read(),bp[i]=read(),as[i]=read(),bs[i]=read();        memset(dp,-0x3f,sizeof(dp));        dp[0][0]=0;        for (int i=1;i<=w+1;++i)            for (int j=0;j<=min(as[i],m);++j)                dp[i][j]=-ap[i]*j;        for (int i=1;i<=n;++i) {            for (int j=0;j<=m;++j)                dp[i][j]=max(dp[i-1][j],dp[i][j]);            if (i<=w+1) continue;            int pre=i-w-1;            h=1,t=0;            for (int j=0;j<=m;++j) {                while (h<=t&&q[h]+as[i]<j) ++h;                if (q[h]<=j) dp[i][j]=max(dp[i][j],dp[pre][q[h]]-ap[i]*(j-q[h]));                while (h<=t&&dp[pre][q[t]]-ap[i]*(j-q[t])<dp[pre][j]) --t;                q[++t]=j;            }            h=1,t=0;            for (int j=m;~j;--j) {                while (h<=t&&q[h]-bs[i]>j) ++h;                if (q[h]>=j) dp[i][j]=max(dp[i][j],dp[pre][q[h]]+bp[i]*(q[h]-j));                while (h<=t&&dp[pre][q[t]]+bp[i]*(q[t]-j)<dp[pre][j]) --t;                q[++t]=j;            }        }        int ans=0;        for (int j=0;j<=m;++j)            ans=max(ans,dp[n][j]);        printf("%d\n",ans);    }    return 0;}