我终于打传送门了
我们发现这道题长得非常像dp。但这不是简单的dp。(这不是废话吗 )我们发现这个dp的转移是不能单单用一个循环做(因为限制不同)。故我们分为4种情况讨论并分别dp。
我们先定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为第i天手上有的股票数。
- 不买不卖 我们就从前一个状态上搞。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 只买不卖 这里发现其实这种情况也分为2种情况:
<3>以前没有 d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , − i n [ i ] . p ∗ j ) dp[i][j]=max(dp[i][j],-in[i].p*j) dp[i][j]=max(dp[i][j],−in[i].p∗j)
<4>以前有 d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − w − 1 ] [ k ] − ( j − k ) ∗ i n [ i ] . p ) ( j − i n [ i ] . s < = k < = j ) dp[i][j]=max(dp[i][j],dp[i-w-1][k]-(j-k)*in[i].p)(j-in[i].s<=k<=j) dp[i][j]=max(dp[i][j],dp[i−w−1][k]−(j−k)∗in[i].p)(j−in[i].s<=k<=j)。我们由于1操作,只用让 i − w − 1 i-w-1 i−w−1来比较。 - 只卖不买 d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − w − 1 ] [ k ] + ( k − j ) ∗ o u t [ i ] . p ) ( j < = k < = j + o u t [ i ] . s ) dp[i][j]=max(dp[i][j],dp[i-w-1][k]+(k-j)*out[i].p)(j<=k<=j+out[i].s) dp[i][j]=max(dp[i][j],dp[i−w−1][k]+(k−j)∗out[i].p)(j<=k<=j+out[i].s)
然后,就上马吧!(加了单调队列优化)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 2002;
struct node {
int p, s;
}in[N], out[N];
int n, limit, w, head, tail, dp[N][N], q[N];
int main() {
memset(dp, -0x3f, sizeof dp);
scanf("%d %d %d", &n, &limit, &w);
for(int i = 1; i <= n; i ++) {//为什么四个搞在一个循环?前面的会对后面有影响,有些操作需要更新。
scanf("%d %d %d %d", &in[i].p, &out[i].p, &in[i].s, &out[i].s);
for(int j = 0; j <= limit; j ++)
dp[i][j] = dp[i - 1][j];
for(int j = 0; j <= in[i].s; j ++)
dp[i][j] = max(dp[i][j], -in[i].p * j);
if(i > w + 1) {//减出来1维至少是1
head = 1;
tail = 0;
for(int j = limit; j >= 0; j --) {//这里因为k的取值要反着打
for(; head <= tail && q[head] > j + out[i].s; head ++);
for(; head <= tail && dp[i - w - 1][j] + j * out[i].p >= dp[i - w - 1][q[tail]] + q[tail] * out[i].p; tail --);
q[++ tail] = j;//要先插入队列再做,可能队列没有值
dp[i][j] = max(dp[i][j], dp[i - w - 1][q[head]] + q[head] * out[i].p - j * out[i].p);
}
head = 1;
tail = 0;
for(int j = 0; j <= limit; j ++) {
for(; head <= tail && q[head] < j - in[i].s; head ++);
for(; head <= tail && dp[i - w - 1][j] + j * in[i].p >= dp[i - w - 1][q[tail]] + q[tail] * in[i].p; tail --);
q[++ tail] = j;
dp[i][j] = max(dp[i][j], dp[i - w - 1][q[head]] + q[head] * in[i].p - j * in[i].p);
}
}
}
printf("%d\n", dp[n][0]);//此时代表第n天拥有0张股票,显然这是最优的
return 0;
}
如有问题,请在评论区指出,谢谢!