P r o b l e m \mathrm{Problem} Problem
S o l u t i o n \mathrm{Solution} Solution
设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-1][j]) f[i][j]=max(f[i][j],f[i−1][j]) - 所有股票都是今天买的
f [ i ] [ j ] = max ( f [ i ] [ j ] , j ∗ A p i ) f[i][j]=\max(f[i][j],j*Ap_i) f[i][j]=max(f[i][j],j∗Api) - 买股票
f [ i ] [ j ] = max j − A s i ≤ k < j ( f [ i ] [ j ] , f [ i − w − 1 ] [ k ] − ( j − k ) ∗ A p i ) f[i][j]=\max_{j-As_i\leq k<j}(f[i][j],f[i-w-1][k]-(j-k)*Ap_i) f[i][j]=j−Asi≤k<jmax(f[i][j],f[i−w−1][k]−(j−k)∗Api) - 卖股票
f [ i ] [ j ] = max j < k ≤ j + B s i ( f [ i ] [ j ] , f [ i − w − 1 ] [ k ] + ( k − j ) ∗ B p i ) f[i][j]=\max_{j< k\leq j+Bs_i}(f[i][j],f[i-w-1][k]+(k-j)*Bp_i) f[i][j]=j<k≤j+Bsimax(f[i][j],f[i−w−1][k]+(k−j)∗Bpi)
这显然是很简单了,我们再来考虑一下如何单调队列。
首先对于买股票的操作,单调队列一开始肯定要是空的,因为没有决策会小于0的。
对于卖股票的操作,由于需要逆序的操作,而且一开始的m一定在 j + B s i j+Bs_i j+Bsi的范围内,所有要有一个 m m m。
C o d e \mathrm{Code} Code
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2100;
int n, m, w;
int Ap[N], Bp[N], As[N], Bs[N], f[N][N], q[N];
int read(void)
{
int s = 0, w = 0; char c = getchar();
while (c < '0' or c > '9') w |= c == '-', c = getchar();
while (c >= '0' and c <= '9') s = s*10+c-48, c = getchar();
return w ? -s : s;
}
int main(void)
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
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();
memset(f,-30,sizeof f);
f[0][0] = 0;
for (int i=1;i<=n;++i)
{
for (int j=0;j<=As[i];++j) f[i][j] = -j * Ap[i];
for (int j=0;j<=m;++j) f[i][j] = max(f[i][j],f[i-1][j]);
if (i - w - 1 < 0) continue;
#define calc1(e) (f[i-w-1][e]+e*Ap[i])
#define calc2(e) (f[i-w-1][e]+e*Bp[i])
int h = 1, t = 0;
for (int j=0;j<=m;++j)
{
while (h <= t and q[h] < j-As[i]) h ++;
if (h <= t) f[i][j] = max(f[i][j],calc1(q[h]) - j * Ap[i]);
while (h <= t and calc1(j) >= calc1(q[t])) t --;
q[++t] = j;
}
h = 1, t = 1;q[1] = m;
for (int j=m;j>=0;--j)
{
while (h <= t and q[h] > j+Bs[i]) h ++;
if (h <= t) f[i][j] = max(f[i][j],calc2(q[h]) - j * Bp[i]);
while (h <= t and calc2(j) >= calc2(q[t])) t --;
q[++t] = j;
}
}
printf("%d\n", f[n][0]);
return 0;
}