题目描述
最近 ext{lxhgww}lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察, ext{lxhgww}lxhgww 预测到了未来 TT 天内某只股票的走势,第 ii 天的股票买入价为每股 AP_iAPi,第 ii 天的股票卖出价为每股 BP_iBPi(数据保证对于每个 ii,都有 AP_i geq BP_iAPi≥BPi),但是每天不能无限制地交易,于是股票交易所规定第 ii 天的一次买入至多只能购买 AS_iASi 股,一次卖出至多只能卖出 BS_iBSi 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 WW 天,也就是说如果在第 ii 天发生了交易,那么从第 i+1i+1 天到第 i+Wi+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 ext{MaxP}MaxP。
在第 11 天之前, ext{lxhgww}lxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,TT 天以后, ext{lxhgww}lxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据第一行包括 33 个整数,分别是 TT, ext{MaxP}MaxP,WW。
接下来 TT 行,第 ii 行代表第 i-1i−1 天的股票走势,每行 44 个整数,分别表示 AP_i, BP_i, AS_i, BS_iAPi, BPi, ASi, BSi。
输出格式:
输出数据为一行,包括 11 个数字,表示 ext{lxhgww}lxhgww 能赚到的最多的钱数。
输入输出样例
说明
对于 30\%30% 的数据,0leq W<Tleq 50,1leq ext{MaxP}leq500≤W<T≤50,1≤MaxP≤50
对于 50\%50% 的数据,0leq W<Tleq 2000,1leq ext{MaxP}leq500≤W<T≤2000,1≤MaxP≤50
对于 100\%100% 的数据,0leq W<Tleq 2000,1leq ext{MaxP}leq20000≤W<T≤2000,1≤MaxP≤2000
对于所有的数据,1leq BP_ileq AP_ileq 1000,1leq AS_i,BS_ileq ext{MaxP}1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP
题意:
一共t天,最多可以持有maxp支股票。给定每天股票买入卖出价格和每天的交易限额。问可以最多赚多少钱。
思路:
应该能够想得到这是一个dp。子结构就是前i天能赚取的最多价格,这就是“阶段”,也就是第一维。同时我们还需要记录一下持有的股票数,因为状态转移时,不同的股票数的转移是不同的。
因此,dp[i][j]表示第i天持有j的时候所能赚取的最大值。
对于每一天我们都有三种情况。
1.不买也不卖。 那么转移方程就是
2.买入。买入有分两种情况,一种是之前什么都没有,这j股都是在第i天买的。
另一种是之前的某一天买了k股,今天买了j-k股。而且题目要求两个交易的日子要间隔w天。
3.卖出。之前的某一天有k股,卖掉了k-j股,第i天剩下j股。
但是我们会发现状态转移的时候如果枚举k,会出现O(n^3)的复杂度,需要进一步优化。
观察状态转移方程我们可以把k合并同类项,比如卖出的式子可以变成
由于max{}中的是一个正数,假设我们设在j时这个值为x,扩展到j+1时,我们只有可能取x或者k=j时的值。他是一个递增的选择。
就可以用单调队列来维护这个值了。
由于卖出是由比j大的k推出的,所以在转移卖出这种情况的时候,j应该是逆序的。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 #include <bits/stdc++.h> 11 using namespace std; 12 typedef long long LL; 13 #define inf 0x7f7f7f7f 14 15 const int maxn = 2005; 16 int t, maxp, w; 17 struct node{ 18 int ap, bp, as, bs; 19 }day[maxn]; 20 int dp[maxn][maxn], que[maxn]; 21 22 int main() 23 { 24 scanf("%d%d%d", &t, &maxp, &w); 25 memset(dp, -inf, sizeof(dp)); 26 for(int i = 1; i <= t; i++){ 27 scanf("%d%d%d%d", &day[i].ap, &day[i].bp, &day[i].as, &day[i].bs); 28 } 29 for(int i = 1; i <= t; i++){ 30 for(int j = 0; j <= day[i].as; j++){ 31 dp[i][j] = -j * day[i].ap; 32 } 33 for(int j = 0; j <= maxp; j++){ 34 dp[i][j] = max(dp[i][j], dp[i - 1][j]); 35 } 36 if(i <= w)continue; 37 int head = 1, tail = 0; 38 for(int j = 0; j <= maxp; j++){ 39 while(dp[i - w - 1][que[tail]] + que[tail] * day[i].ap <= dp[i - 1 - w][j] + j * day[i].ap && head <= tail){ 40 tail--; 41 } 42 que[++tail] = j; 43 while(j - que[head] > day[i].as){ 44 head++; 45 } 46 dp[i][j] = max(dp[i][j], dp[i - w - 1][que[head]] - (j - que[head]) * day[i].ap); 47 } 48 49 head = 1, tail = 0; 50 for(int j = maxp; j >= 0; j--){ 51 while(dp[i - w - 1][que[tail]] + que[tail] * day[i].bp <= dp[i - 1 - w][j] + j * day[i].bp && head <= tail){ 52 tail--; 53 } 54 que[++tail] = j; 55 while(que[head] - j > day[i].bs){ 56 head++; 57 } 58 dp[i][j] = max(dp[i][j], dp[i - 1 - w][que[head]] + (que[head] - j) * day[i].bp); 59 } 60 } 61 62 63 int ans = -1; 64 for(int j = 0; j <= maxp; j++){ 65 ans = max(ans, dp[t][j]); 66 } 67 printf("%d ", ans); 68 return 0; 69 }