0%

HDU 2026 春季联赛 10 D - 歪歪爱追剧

题目大意

题面

歪歪要追 T 集电视剧。对每一集,电视剧长度为 L 分钟,她预先给出 n 个可能想看的片段,第 i 个片段是闭区间 [l_i, r_i]。

她会从这些片段里选出若干个两两不重叠的片段。注意这里是闭区间,所以 [1, 3] 和 [3, 5] 算重叠,[1, 3] 和 [4, 5] 才不重叠。

同时,男明星会在这一集的 m 个时刻出现,分别是 a_i。歪歪要求每个被选择的片段里,都至少能看到一次男明星。

问在这个前提下,一集最多能看多少分钟。

输入格式

第一行输入 T。

每组数据先输入 L, n, m。

接下来 n 行输入 l_i, r_i。

最后一行输入 m 个 a_i。

数据范围

  • T <= 10

  • L <= 1e9

  • n, m <= 1e5

  • 1 <= a_i <= L

  • 1 <= l_i <= r_i <= L

样例

1
2
3
4
5
6
7
8
9
10
11
2
10 5 3
1 2
3 3
1 6
4 10
8 10
1 3 10
10 1 5
6 10
1 2 3 4 5

输出:

1
2
10
0

思路讲解

一句话

先用二分筛掉“不含明星出现时刻”的片段,剩下的问题就是经典的带权区间选择:每个合法区间的权重是长度,按右端点排序后做 DP。

第一步:判断一个片段能不能看

把所有明星出现时刻 a_i 排序。对片段 [l, r],用 lower_bound(a, l) 找到第一个 >= l 的出现时刻。

如果这个位置存在,并且值 <= r,说明片段里至少出现了一次男明星,这个片段可以进入后面的 DP。

这个筛选是 O(log m) 的,所以 n 个片段总共 O(n log m)。

第二步:把问题看成带权区间选择

筛完以后,每个片段都有一个权重:

w=rl+1w = r - l + 1

现在要从这些区间里选若干个互不重叠的区间,让权重和最大。

闭区间的边界非常关键:前一个区间的右端点必须严格小于当前区间左端点,也就是 r_prev < l_now。

按右端点从小到大排序。设 dp[i] 表示只考虑前 i 个合法区间时,最多能看的分钟数。

对当前区间 [l_i, r_i],有两种选择:

  • 不选它:答案是 dp[i - 1]

  • 选它:找到最后一个满足 r_j < l_i 的区间 j,答案是 dp[j] + w_i

于是转移就是:

dp[i]=max(dp[i1],dp[j]+wi)dp[i] = max(dp[i - 1], dp[j] + w_i)

这里 j 可以用 lower_bound(right, l_i) - 1 找到。

第三步:为什么要考虑“单独选当前区间”

这题最容易挂的地方不是大方向,而是这个小分支。

如果当前区间前面没有任何能接上的前驱,也就是 lower_bound(right, l_i) 指向开头,它仍然可以单独选。

所以当前区间的贡献至少应该参与一次比较:

1
dp[i] = max(dp[i - 1], lr[i].w);

然后如果存在前驱,再尝试:

1
dp[i] = max(dp[i], dp[j] + lr[i].w);

反例很小:

1
2
3
4
5
1
100 2 2
1 5
2 100
1 2

两个区间都合法,但互相重叠。最优应该单独选 [2, 100],答案是 99。若没有“单独选当前区间”这个分支,就会错误地保留 [1, 5],输出 5。

复杂度

排序明星出现时刻、排序区间,再对每个片段二分一次。

总复杂度 O((n + m) log n),空间 O(n + m)。

AC 代码

AC 提交链接

源码较长,折叠放在下面。

心路历程(WA,TLE,MLE……)

  • 一开始 DP 大方向是对的:合法片段筛选 + 按右端点排序 + 找前驱。

  • 坑点出在当前区间没有前驱的时候,代码直接 continue,漏掉了“当前区间单独作为答案”的情况。

  • 修法是先执行 dp[i] = max(dp[i - 1], lr[i].w),再在存在前驱时尝试拼上前驱。

  • 这类带权区间 DP 可以记一句话:当前区间要么不选,要么自己开一段,要么接在一个合法前驱后面。

附件

暂无额外附件。