CF480D Parcels 题解
题目链接:CF480D Parcels
题意:
有 $n$ 件包裹,每个包裹是一个盒子,都有它自身的质量和载重 (即它上方能承受的最大质量)。cxy 最近得到了一个新的包裹处理系统,这个系统以如下方式工作。初始时,有一个(可以堆放盒子的)平台,它的载重为 $S$,接下来,你能以如下的规则在平台上堆放盒子:
- 如果平台是空的,你可以将盒子堆放在平台上,否则,你只能在新的盒子放在最高的盒子上面。
- 任何时刻,(平台上)所有盒子的总质量不能超过 $S$ (即平台的载重)。
- 对任意一个盒子,任何时刻,在它上面的所有盒子的总质量不能超过这个盒子的载重。
- 并且你只能取走当前位于最上面的盒子(即形成栈型结构)。
系统接收到了这 $n$ 件包裹,已知第 $i$ 个包裹在时刻 $\text{in}_i$ 出现,它的质量和载重分别为 $w_i,s_i$,每个包裹都有它的价值,其中第 $i$ 个包裹的价值为 $v_i$。然而,为了获得(赚得)这 $v_i$ 的价值,这个系统要求它刚好在时刻 $\text{out}_i$ 被出售,否则将无法获得任何价值。于是,cxy 可以选择跳过部分包裹(即不接收这些包裹),当然她也无法获得任何价值。
任何操作所花费的时间可以忽略不计,这意味着你可以在一个时刻做多件事情(比如取走若干包裹,在堆放若干包裹)。
注意一旦一个包裹被取走后,它就不会影响后续对包裹的操作。
由于这系统非常复杂,并且包裹数有很多,cxy 想要知道如果她合理利用这个系统,她最多能得到多少钱。
输入格式:
第一行包含两个非负整数 $n,S(n≤500,S≤1000)$ ,表示包裹的个数和平台的载重。
接下来的 $n$ 行,每行包含 $5$ 个非负整数 $\text{in}_i,\text{out}_i,w_i,s_i,v_i(0\le\text{in}_i<\text{out}_i<2n,~0 \le w_i,s_i\le 1000,~1\le v_i\le 10^6)$,
保证不存在两个包裹的出现时间 ($\text{in}_i$) 和出售时间 ($\text{out}_i$) 均相同。
输出格式:
输出一行一个整数,表示 cxy 能得到的价值的最大值。
容易发现,时间有交集的两个包裹,如果他们不是包含关系,则一定只能二选一。
但如果是包含关系,这俩就都可以选。并且在一个大集合内,可以选若干个小的。
再加上这个栈的性质,很容易把它和树联系到一起。
我们把每个包裹按右端点排序,则若 $v$ 是 $u$ 的子节点,$v$ 一定出现的比 $u$ 早,这就方便dp了。
设 $f_{i,j}$ 表示对于第 $i$ 个包裹(节点),当前剩余的最大载重量为 $j$ ,$i$ 所在子树中的最大价值。
注意,由于原图可能是个森林,所以我们要加个虚拟节点(平台)把它们连起来。
考虑转移。设 $g_b (\text{in}_i \le b \le \text{out}_i)$ 表示到时刻 $b$ 位置的最大价值,则对于 $i$ 的某个子节点 $u$ ,当 $b = \text{out}_u$ 时
最后别忘了它自己, $f_{i,j}=g_{\text{out}_i} + v_i$ 。最终答案就是虚拟点载重为 $S$ 的答案。
时间复杂度 $\mathcal{O}(n^3)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(555))
#define M ((int)(1e3 + 15))
struct node
{
int i,o,w,s,v;
void read() { cin >> i >> o >> w >> s >> v; }
friend bool operator < (node a, node b) {
return a.o == b.o ? (a.i > b.i) : (a.o < b.o);
}
}p[N];
int n,S,f[N][M],g[M];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n >> S; p[0] = {0, (n << 1 | 1), 0, S, 0};
for(int i = 1; i <= n; i++) { p[i].read(); } sort(p, p + 1 + n);
for(int i = 0; i <= n; i++)
for(int j = p[i].w; j <= S; j++)
{
int b = p[i].i, nj = min(j - p[i].w, p[i].s); g[b] = 0;
for(int k = 0; k < i; k++)
if(p[i].i <= p[k].i)
{
for(; b < p[k].o; b++) g[b + 1] = g[b];
up(g[b], g[p[k].i] + f[k][nj]);
}
f[i][j] = g[b] + p[i].v;
}
cout << f[n][S] << '\n';
return 0;
}
参考文献:
[1] https://yhx-12243.github.io/OI-transit/records/cf480D.html