【SCOI2010】股票交易

Description

【SCOI2010】股票交易

在T天时间内,第\(i\)天股票购入价为\(ap_i\),出售价为\(bp_i\),每天最多购入\(as_i\)股,最多出售\(bs_i\)股

任意时刻手中的股票数不能超过\(Maxp\),且两次交易至少间隔\(W\)天

最大化收益,初始资金视为无限大

Solution

单调队列+dp

根据题意不难设计状态,定义\(f[i][j]\)表示前\(i\)天,手里最后有\(j\)个股票的最大收益,那么状态转移方程就是:
\[
f[i][j]=
\begin{cases}
f[i-1][j] \f[i-w-1][k]-ap[i]*(j-k) & k\in[j-as[i],j)\f[i-w-1][k]+bp[i]*(k-j) & k\in(j,j+bs[i]]
\end{cases}
\]
以第二个式子为例,我们可以变形得到\(f[i][j]=f[i-w-1][k]+ap[i]*k-ap[i]*j\)

这个式子符合单调队列的一半形式,所以我们可以用单调队列进行优化

第三个式子同理

时间复杂度为\(O(TMaxp)\)

Code

#include <bits/stdc++.h>
// check if it is judged online
namespace shl {
    typedef long long ll;
    inline int read() {
        int ret = 0, op = 1;
        char c = getchar();
        while (!isdigit(c)) {
            if (c == '-') op = -1;
            c = getchar();
        }
        while (isdigit(c)) {
            ret = ret * 10 + c - '0';
            c = getchar();
        }
        return ret * op;
    }
    const int N = 2010;
    int n, m, w;
    int as[N], bs[N], ap[N], bp[N];
    int head, tail, que[N];
    int f[N][N];
    inline int calca(int i, int ww, int k) {
        return f[i - ww - 1][k] + ap[i] * k;
    }
    inline int calcb(int i, int ww, int k) {
        return f[i - ww - 1][k] + bp[i] * k;
    }
    using std::max;
    int main() {
        n = read(), m = read(), w = read();
        for (register int i = 1; i <= n; ++i) {
            ap[i] = read(), bp[i] = read(), as[i] = read(), bs[i] = read();
        }
        memset(f, -0x7f, sizeof(f));
        for (register int i = 0; i <= n; ++i)  f[i][0] = 0;
        for (register int i = 1; i <= n; ++i) {
            for (register int j = 0; j <= as[i]; ++j) f[i][j] = -ap[i] * j;
            for (register int j = m; j >= 0; --j) f[i][j] = max(f[i][j], f[i - 1][j]);
            if (i - w - 1 < 0) continue ;
            head = 1, tail = 0;
            for (register int j = 0; j <= m; ++j) {
                while (head <= tail && que[head] < j - as[i]) head++;
                while (head <= tail && calca(i, w, j) >= calca(i, w, que[tail])) tail--;
                que[++tail] = j;
                if (head <= tail) f[i][j] = max(f[i][j], calca(i, w, que[head]) - j * ap[i]);
            }
            head = 1, tail = 0;
            for (register int j = m; j >= 0; --j) {
                while (head <= tail && que[head] > j + bs[i]) head++;
                while (head <= tail && calcb(i, w, j) >= calcb(i, w, que[tail])) tail--;
                que[++tail] = j;
                if (head <= tail) f[i][j] = max(f[i][j], calcb(i, w, que[head]) - j * bp[i]);
            }
        }
        int ans = 0;
        for (register int i = 0; i <= m; ++i) ans = max(ans, f[n][i]);
        printf("%d\n", ans);
        return 0;
    }
}
int main() {
#ifdef LOCAL
    freopen("textname.in", "r", stdin);
    freopen("textname.out", "w", stdout);
#endif
    shl::main();
    return 0;
}

原文地址:https://www.cnblogs.com/shl-blog/p/11618263.html

时间: 2024-11-25 23:36:46

【SCOI2010】股票交易的相关文章

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

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=

洛谷P2569 [SCOI2010]股票交易

P2569 [SCOI2010]股票交易 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股. 另外,股票交易所还制定了两个规定.为了避免大家疯狂交易,股票交易所规

[SCOI2010]股票交易

[SCOI2010]股票交易 推荐的相关题目显示 题目描述 最近 lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww 预测到了未来 T 天内某只股票的走势,第 i 天的股票买入价为每股 APi?,第 i 天的股票卖出价为每股 BPi?(数据保证对于每个 i,都有 APi?≥BPi?),但是每天不能无限制地交易,于是股票交易所规定第 i 天的一次买入至多只能购买 ASi? 股,一次卖出至多只能卖出 BSi? 股. 另外,股票交

bzoj 1855: [Scoi2010]股票交易

Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股. 另外,股票交易所还制定了两个规定.为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或

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

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

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

题意:链接 方法:单调队列优化DP 解析:噢又是一道情况很多的题,然而三种更新我又落下一种导致样例不过,后来看题解才恍然- -最SB的一种更新居然忘了. 状态好想f[i][j]代表前i天有j双袜子时的最大利润. 三种更新: 第一种:f[i][j]=max(f[i][j],f[i?1][j]):(然而我忘了这一种) 第二种:买入f[i][j]=max(f[i][j],f[i?w?1][k]?(j?k)?a[i].ap)(k>=j?a[i].as); 第三种:卖出f[i][j]=max(f[i][j

●BZOJ 1855 [Scoi2010]股票交易

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1855 题解: DP,单调队列优化.(好久没做 DP题,居然还意外地想出来了) 定义 dp[i][k] 表示前 i天,手上还有 k股的最大收益.(注意这个定义是个前缀的形式)假设枚举到了第 i天,令 j=i-W-1.那么dp[i][]就由dp[j][]转移而来.(说了是前缀形式的啦,就不要去枚举 j-1,j-2...了)转移还是比较显然的:枚举第 i 天结束手上还剩的股数 k:      

Bzoj1855: [Scoi2010]股票交易

题面 Bzoj Sol 设\(f[i][j]\)表示第\(i\)天有\(j\)张股票的最大收益 转移很简单辣 # include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(2010); IL int Input(){ RG int

洛谷 [SCOI2010]股票交易 | 单调性DP

题目链接 #include<cstdio> #include<algorithm> #include<cstring> #define N 2005 using namespace std; int n,q[N],ap,bp,dp[N][N],as,bs,m,w; int main() { scanf("%d%d%d",&n,&m,&w); memset(dp,128,sizeof(dp)); for (int i=1;i&l

【bzoj1855】 [Scoi2010]股票交易

上一篇blog已经讲了单调队列与单调栈的用法,本篇将讲述如何借助单调队列优化dp. 我先丢一道题:bzoj1855 此题不难想出O(n^4)做法,我们用f[i][j]表示第i天手中持有j只股票时,所赚钱的最大值. 不难推出以下式子: $f[i][j]=max\left\{\begin{aligned}f[k][l]+(l-j)\times bs[i] , l \in [j,j+bs[i]]\\f[k][l]-(j-l)\times as[i] , l \in [j-as[i],j]\\\end{