【[SCOI2010]股票交易】

感谢dzm,尽管接受了\(The \text{ }\text{ }king\text{ } \text{ }of\text{ } \text{ }SD\)的指点但我还是不会

至少方程还是比较好推的

状态还是很常规的,我们设\(f[i][j]\)表示在第\(i\)天持有\(j\)只股票的最大收益是多少

于是我们有三种转移

  • \(f[i][j]=f[i-1][j]\)

这就相当于你这一天什么都没干,前一天持有多少股票这一天还是持有多少股票

  • \(f[i][j]=max(f[i-w-1][j+k]+k*b[i])\) (\(k<=y[i]\))

这一天卖出了\(k\)只股票

  • \(f[i][j]=max(f[i-w-1][j-k]-k*a[i]\) (\(k<=a[i]\))

这一天买进了\(k\)只股票

这样暴力转移的话复杂度是\(O(nm^2)\),显然是\(O(\text{TLE})\)

于是我们考虑单调队列优化

显然方程写成这个样子优化不了

我们换个写法

第一个方程我们写成这个样子

\(f[i][j]=max(f[i-w-1][k]+(k-j)*b[i])\) \(\text{ }\) \(k>=j\)\(k<=j+y[i]\)

于是拆一下变成

\(f[i][j]=max(f[i-w-1][k]+k*b[i]-j*b[i])\)

前面两项跟\(j\)无关于是我们可以用单调队列来优化

至于第二个方程也是同理,拆开是这个样子

\(f[i][j]=max(f[i-w-1][k]+k*a[i]-j*a[i])\)

于是也可以用单调队列来优化

复杂度变为\(O(nm)\)

还有一个坑点就是如果前\(i-1\)天什么都没干

那么\(f[i][j]=0-i*a[i]*j\)

这个状态也要考虑到,否则就只有60

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define re register
#define LL long long
#define maxn 2005
#define INF -99999999
using namespace std;
int f[maxn][maxn];
int a[maxn],b[maxn],x[maxn],y[maxn];
int dp[maxn],d[maxn];
int n,m,t;
deque<int> q1[maxn],q2[maxn];
inline int read()
{
    char c=getchar();
    int X=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
      X=(X<<3)+(X<<1)+c-48,c=getchar();
    return X;
}
int main()
{
    n=read();
    m=read();
    t=read();
    for(re int i=0;i<=n;i++)
        for(re int j=0;j<=m;j++) 
            f[i][j]=INF;
    for(re int i=1;i<=n;i++)
    {
        a[i]=read();
        b[i]=read();
        x[i]=read();
        y[i]=read();
    }
    for(re int i=0;i<=x[1];i++)
        f[1][i]=0-a[1]*i;
    for(re int i=2;i<=n;i++)
    {
        for(re int j=0;j<=m;j++)
            dp[j]=d[j]=INF;
        int k=i-t-1;
        if(k>=0)
        {
            deque<int> q;
            for(re int j=m;j>=0;j--)
            {
                while(!q.empty()&&f[k][q.back()]+q.back()*b[i]<f[k][j]+j*b[i]) q.pop_back();
                q.push_back(j);
                while(!q.empty()&&q.front()-j>y[i]) q.pop_front();
                dp[j]=f[k][q.front()]+q.front()*b[i]-j*b[i];
            }
            q.clear();
            for(re int j=0;j<=m;j++)
            {
                while(!q.empty()&&f[k][q.back()]+q.back()*a[i]<f[k][j]+j*a[i]) q.pop_back();
                q.push_back(j);
                while(!q.empty()&&q.front()+x[i]<j) q.pop_front();
                d[j]=f[k][q.front()]+q.front()*a[i]-j*a[i];
            }
        }
        for(re int j=0;j<=m;j++)
        if(j<=x[i]) f[i][j]=max(max(f[i-1][j],max(d[j],dp[j])),-1*a[i]*j);
        else f[i][j]=max(f[i-1][j],max(d[j],dp[j]));
    }
    int ans=INF;
    for(re int i=0;i<=m;i++)
        ans=max(ans,f[n][i]);
    cout<<ans<<endl;
    return 0;
}	
posted @ 2019-01-02 12:01  asuldb  阅读(162)  评论(0编辑  收藏  举报