zoukankan      html  css  js  c++  java
  • 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_ile 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

    正确性我不会证明。

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

    扩展

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

  • 相关阅读:
    markdown样式代码保存
    【python系统学习08】for循环知识点合集
    【python系统学习07】一张图看懂字典并学会操作
    【python系统学习06】一张图看懂列表并学会操作
    java后端学习记录
    支付功能设计及实现思路
    《Kafka权威指南》读书笔记
    ReentrantLock源码简析
    敏捷开发流程
    上线新功能,如何兼容旧数据?
  • 原文地址:https://www.cnblogs.com/Patt/p/12976892.html
Copyright © 2011-2022 走看看