[SCOI2010]股票交易

题面传送


这题好想,dp嘛。但是转移容易漏。
\(dp[i][j]\)表示第\(i\)天,手里有\(j\)股时的最大利润,那么
1.啥也不干:\(dp[i][j] = dp[i - 1][j]\).
2.凭空买(前几天啥也不干):\(dp[i][j] = max \{dp[i][j], -j * ap[i]\}\).(我就漏了这个)
3.在第\(i\)天买\(j-k\)股:\(dp[i][j] = max \{dp[i - w - 1][k] - (j - k) * ap[i] \}(0 \leqslant j-k \leqslant as[i])\).
4.同理,在第\(i\)天卖\(j - k\)股:\(dp[i][j] = max \{dp[i - w - 1][k] + (j - k) * bp[i]\}(0 \leqslant j - k \leqslant bs[i])\).


对于“买”这个式子(卖同理),稍微变形一下:\(dp[i][j] = max \{dp[i - w - 1][k] + k * ap[i] \} - j * ap[i]\),就变成了滑动窗口问题了,单调队列可以解决。


做法就是对于每一层,正着和倒着跑一遍单调队列,分别处理买和卖两个转移。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const ll INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e3 + 5;
In ll read()
{
	ll ans = 0;
	char ch = getchar(), las = ' ';
	while(!isdigit(ch)) las = ch, ch = getchar();
	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
	if(las == '-') ans = -ans;
	return ans;
}
In void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
}

int n, m, w;
int ap[maxn], bp[maxn], as[maxn], bs[maxn];

int dp[maxn][maxn];
deque<int> q;
In void work1()
{
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 0; j <= m; ++j) 
		{
			dp[i][j] = dp[i - 1][j];
			if(j <= as[i]) dp[i][j] = max(dp[i][j], -j * ap[i]); 
		}
		if(i <= w) continue;
		q.clear();
		for(int j = 0; j <= m; ++j)
		{
			int* D = dp[i - w - 1];			
			while(!q.empty() && D[q.back()] + q.back() * ap[i] <= D[j] + j * ap[i]) q.pop_back();
			while(!q.empty() && q.front() < j - as[i]) q.pop_front();
			q.push_back(j);
			dp[i][j] = max(dp[i][j], D[q.front()] - (j - q.front()) * ap[i]);
		}
		q.clear();
		for(int j = m; j >= 0; --j)
		{
			int* D = dp[i - w - 1]; 
			while(!q.empty() && D[q.back()] + q.back() * bp[i] <= D[j] + j * bp[i]) q.pop_back();
			while(!q.empty() && q.front() - j > bs[i]) q.pop_front();	
			q.push_back(j);
			dp[i][j] = max(dp[i][j], D[q.front()] + (q.front() - j) * bp[i]);
		}
	}
	int ans = -INF;
	for(int i = 0; i <= m; ++i) ans = max(ans, dp[n][i]);
	write(ans), enter;
}

int main()
{
	n = read(), m = read(), w = read();
	for(int i = 1; i <= n; ++i)
		ap[i] = read(), bp[i] = read(), as[i] = read(), bs[i] = read();
	Mem(dp, 128), dp[0][0] = 0;
	work1();
	return 0;
}
posted @ 2021-03-10 13:55  mrclr  阅读(60)  评论(0编辑  收藏  举报