CF 1348F Phoenix and Memory

这个问题可以重新表述为:
给你 $n$ 个区间 $[a_i, b_i]$,$1 \le a_i \le b_i \le n$。
这里,区间 $[l, r]$ 指的是正整数集合 $\{l, l+1, \dots, r\}$。
从第 $i$ 个区间中取一个数 $x_i$,也就是说要求 $a_i\le x_i \le b_i$。

  1. 判断是否存在一种取数方案使得所取出的 $n$ 个数两两不同,换言之,使得 $x_1, x_2, \dots, x_n$ 恰是 $1$ 到 $n$ 的一个排列?
  2. 若可能,再判断这样的取数方案是否唯一。若唯一,输出唯一的排列,否则输出任意两个排列。

问题 1。

这是一个经典问题。有两个贪心做法:

贪心做法一

将区间按右端点从小到大排序,按此顺序遍历这些区间,在每个区间中取所能取的最小的那个数。举例言之,有三个区间 $[1, 1], [1, 3], [2, 2]$,排序后是 $[1, 1], [2, 2], [1, 3]$。在 $[1,1]$ 中取 $1$,$[2, 2]$ 中取 $2$,$[1,3]$ 中取 $3$。

贪心做法二

这个做法有 $n$ 个步骤。
$S$ 是一个 multiset,初始为空。

第一步:将左端点等于 $1$ 的区间的右端点加到 $S$ 中。若 $S$ 里的最小值小于 $1$,则无解,否则从 $S$ 里的最小值对应的那个区间中选取 $1$,并把最小值从 $S$ 中删除。

第二步:将左端点等于 $2$ 的区间的右端点加到 $S$ 中。若 $S$ 里的最小值小于 $2$,则无解,否则从 $S$ 里的最小值对应的那个区间中选取 $2$,并把最小值从 $S$ 中删除。

第 $k$ 步:将左端点等于 $k$ 的区间的右端点加到 $S$ 中。若 $S$ 里的最小值小于 $k$,则无解,否则从 $S$ 里的最小值对应的那个区间中选取 $k$,并把最小值从 $S$ 中删除。

此贪心算法的正确性证明:https://codeforces.ml/blog/entry/76555?#comment-613974

容易看出,multiset 可换成小顶堆。

问题 2

顺着上述贪心做法二的思路我们可以判断出取数的方案是否唯一:
在第 $k$ 步中如果 $S$ 中至少有两个元素,并且 $S$ 中的最小值大于 $k$——设 $S$ 中的最小值和次小值对应的区间编号分别为 $i$,$j$——那么我们看能否从区间 $j$ 中取 $k$。如何判断呢?
可以这样做:假设正常情况下从区间 $j$ 取出的数是 $x_j$,我们看一下 $x_j$ 能否从区间 $i$ 中取出。

此解法来自 https://codeforces.ml/blog/entry/76555?#comment-613946

扫描二维码关注公众号,回复: 11281023 查看本文章

正确性我不会证明。

参考实现:https://codeforces.ml/contest/1348/submission/81636889

扩展

如何求有多少个不同的排列?

猜你喜欢

转载自www.cnblogs.com/Patt/p/12976892.html