SCOI2010 股票交易

Posted fengxunling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SCOI2010 股票交易相关的知识,希望对你有一定的参考价值。

题目链接:戳我

看到这个题目,我们有一个朴素的DP想法(但是为什么我会先想到网络流啊喂,果然是菜鸡

\(dp[i][j][0/1/2]\)表示第i天不进行交易/买入/卖出,现在手上有j张票,前i天能够获得的最大收益。转移什么的随便弄弄就行了吧。

然后发现自己智障了,0/1/2根本不用划分好吗.......于是就变成了这个样子......\(dp[i][j]\)表示现在手上有j张票,前i天能够获得的最大收益。

\(dp[i][j]=max(dp[i][j],dp[i-1][j])\)
\(dp[i][j]=max(dp[i][j],dp[i-w-1][k]-ap[i]*(j-k))\)
\(dp[i][j]=max(dp[i][j],dp[i-w-1][k]+bp[i]*(k-j))\)

于是50分到手。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 2010
using namespace std;
int n,m,w;
int ap[MAXN],bp[MAXN],as[MAXN],bs[MAXN];
long long dp[MAXN][MAXN];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&m,&w);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            dp[i][j]=-0x3f3f3f3f3f3f3f3f;
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=m;j++)
        {
            dp[i][j]=max(dp[i][j],dp[i-1][j]);
            for(int k=max(0,j-as[i]);k<=j-1;k++)
            {
                int cur=max(0,i-w-1);
                dp[i][j]=max(dp[i][j],dp[cur][k]-1ll*ap[i]*(j-k));
            }
            for(int k=j+1;k<=m&&k<=j+bs[i];k++)
            {
                int cur=max(0,i-w-1);
                dp[i][j]=max(dp[i][j],dp[cur][k]+1ll*bp[i]*(k-j));
            }
        }
    }
    long long ans=0;
    for(int i=0;i<=m;i++) ans=max(ans,dp[n][i]);
    printf("%lld\n",ans);
    return 0;
}

之后我们考虑一下怎么把这个K给去掉。
把转移方程化一下:
\(dp[i][j]=max(dp[i-1][j])\)
\(dp[i][j]=max(dp[i-w-1][k]+k*ap[i])-ap[i]*j (j-as[i]\le k \le j-1)\)
\(dp[i][j]=max(dp[i-w-1][k]+k*bp[i])+bp[i]*j (j+1\le k\le j+bs[i])\)

我们发现那个取max的部分是可以用单调队列优化的.......
于是就100pts了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define MAXN 2010
using namespace std;
int n,m,w;
int ap[MAXN],bp[MAXN],as[MAXN],bs[MAXN],q[MAXN];
long long dp[MAXN][MAXN];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d",&n,&m,&w);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            dp[i][j]=-0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=n;i++) dp[i][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=as[i];j++) dp[i][j]=-ap[i]*j;
        for(int j=0;j<=m;j++) dp[i][j]=max(dp[i][j],dp[i-1][j]);
        if(i-w-1>=0)
        {
            int head=1,tail=0;
            for(int j=0;j<=m;j++)
            {
                while(head<=tail&&q[head]<j-as[i]) head++;
                while(head<=tail&&dp[i-w-1][j]+ap[i]*j>=dp[i-w-1][q[tail]]+ap[i]*q[tail]) tail--;
                q[++tail]=j;
                dp[i][j]=max(dp[i][j],dp[i-w-1][q[head]]-ap[i]*(j-q[head]));
            }
            head=1,tail=0;
            for(int j=m;j>=0;j--)
            {
                while(head<=tail&&q[head]>j+bs[i]) head++;
                while(head<=tail&&dp[i-w-1][j]+j*bp[i]>=dp[i-w-1][q[tail]]+q[tail]*bp[i]) tail--;
                q[++tail]=j;
                dp[i][j]=max(dp[i][j],dp[i-w-1][q[head]]+bp[i]*(q[head]-j));
            }
        }
    }
    long long ans=0;
    for(int i=0;i<=m;i++) ans=max(ans,dp[n][i]);
    printf("%lld\n",ans);
    return 0;
}

以上是关于SCOI2010 股票交易的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P2569 [SCOI2010]股票交易

Luogu 2569 SCOI2010 股票交易

[SCOI2010]股票交易

BZOJ1855[Scoi2010]股票交易 DP+单调队列

1855: [Scoi2010]股票交易[单调队列优化DP]

[SCOI2010]股票交易