H. Beppa and SwerChat 解题思路
核心问题分析与数学转化
本题要求计算在 9:00 和 22:00 之间,至少上线过一次的其他成员的最少人数。
设 $A$ 是 9:00 时成员的列表, $B$ 是 22:00 时成员的列表。列表按照最后一次上线时间递减排序。
- 关键观察: 如果一个成员 $X$ 在 9:00 到 22:00 之间没有上线,那么他在 22:00 时的最后上线时间就是他在 9:00 时的最后上线时间(或者更早)。
- 排序推论: 对于所有没有上线的成员构成的子集 $U$,他们在列表 $A$ 中的相对顺序和在列表 $B$ 中的相对顺序必须是完全相同的。
因此,最少上线过的人数 $\text{MinOnline}$ 对应于 最多没有上线的人数 $\text{MaxOffline}$:
$$ \text{MinOnline} = N - \text{MaxOffline} $$ 我们的目标转化为:从 $A$ 和 $B$ 中找到能够保持相对顺序的最长公共子序列,这个子序列代表了 $\text{MaxOffline}$ 的长度。1. 相对顺序的转换与简化
序列 $A$ 和 $B$ 都是 ID 列表。我们首先需要将 $B$ 列表转化为基于 $A$ 列表的排名或索引。
- 定义 $A$ 的排名: 在 9:00 的列表 $A$ 中,成员 $a_i$ 的排名定义为其在 $A$ 中的位置索引 $i+1$ (即 $1$ 到 $N$)。
转换 $B$ 列表: 将 22:00 的列表 $B$ 中的每个 ID 替换为该 ID 在 $A$ 列表中的排名。设转换后的列表为 $B’$。
- $B’$ 的含义:列表中 $B’_j = k$ 表示在 22:00 排在第 $j$ 位的成员,在 9:00 是排在第 $k$ 位的。
寻找 $\text{MaxOffline}$: 如果成员集合 $U$ 没有上线,那么:
- 他们在 $A$ 中的顺序是递减的排名 $k_1 > k_2 > \dots$。
他们在 $B$ 中的顺序也必须是递减的排名 $k_1’ > k_2’ > \dots$。
由于我们已经将 $B$ 转换成了 $A$ 的排名 $B’$,我们现在只需要在 $B’$ 中寻找一个子序列,使得索引递增,且元素值递增(即 $A$ 的排名递增)。
推论: 最多没有上线的人数 $\text{MaxOffline}$ 等于 $B’$ 列表(已转换成 $A$ 排名)中,从后向前找到的最长连续递增子序列的长度。
2. 动态规划思路 (等效于线性扫描)
在 $B'$ 中,我们要找一个最长的后缀子序列 $B'_{i}, B'_{i+1}, \dots, B'_{N-1}$,满足 $B'_j < B'_{j+1}$。我们从 $B’_{N-2}$ 的倒数第二个元素开始向前扫描:
- 初始化: 最长连续递增后缀长度 $\text{Length} = 1$ (包含 $B'_{N-1}$ 本身)。
- 递推: 当我们遍历到索引 $i$ 时,如果 $B'_i < B'_{i+1}$,说明当前成员 $B'_i$ 比后面的 $B'_{i+1}$ 在 9:00 时排名靠前,且在 22:00 时也排在 $B'_{i+1}$ 前面。这保持了相对顺序, $\text{Length} \leftarrow \text{Length} + 1$。
- 中断: 如果 $B'_i \ge B'_{i+1}$,则相对顺序发生变化,说明 $B'_i$ 或之前的某个成员一定上线过。我们在此中断,得到最大长度 $\text{MaxOffline} = \text{Length}$。
最终答案:
$\text{MinOnline} = N - \text{Length}$。
C++ 代码实现
代码中,我们首先使用 map 将 $A$ 列表的 ID 映射到其排名(1到N),然后用这些排名构建 $B’$ 列表,最后通过线性扫描计算最长连续递增后缀的长度。
1 |
|

