• 【[SCOI2010]股票交易】


    感谢dzm,尽管接受了(The ext{ } ext{ }king ext{ } ext{ }of ext{ } ext{ }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( ext{TLE}))

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

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

    我们换个写法

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

    (f[i][j]=max(f[i-w-1][k]+(k-j)*b[i])) ( ext{ }) (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;
    }	
    
  • 相关阅读:
    oc之数组反序输出示例
    OC--有这么一个 整数 123456789,如何将这个整数的每一位数,从末位开始依次放入数组中,并遍历 倒序输出字符串
    oc--截取字符串(从网址中截取用户名和密码)
    iOS 第七期考核题(字符串以及字典的使用 数组内容转换成字符串)
    iOS 第六期考核题(字典的使用)
    iOS 第五期考核题(字典与数组嵌套,字典的排序/删除)
    Linux服务启动报错日志分析
    新手Linux命令-1
    新手Linux命令-2
    计划任务服务
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207806.html
Copyright © 2020-2023  润新知