ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1718D 题解

2022-09-08 08:00:47  阅读:195  来源: 互联网

标签:二分 匹配 一个 题解 CF1718D 一段 区间 贪心


设 \(k\) 为 \(a\) 中的空位数量。

首先咱们转化这个“相似”的条件,发现它其实是说,笛卡尔树的结构相同。

那么我们把p建笛卡尔树然后把a的数往上填。如果此时有上面小于下面就挂了(挂了:即每个询问答案都是NO)

然后对于中间的空,它需要 \(>\) 下面的最大值,并且 \(<\) 上面的最小值。设点 \(i\) 的这个区间为 \([l_i,r_i]\)

接下来我们发现,我们只需要把集合 \(S\) 中的数和 \(d\) 填到这些空里满足 \([l_i,r_i]\) 的限制即可。

为啥:

对于一条连续的空(中间没有确定值),此时它们的区间限制都相同,那就可以任意交换位置。因此只要排序后从下往上填,一定可以满足笛卡尔树上大下小的性质,并且和区间限制不冲突。

如果中间有确定值,那因为这个值的"分隔"作用,上面的区间的 \(l\) 肯定大于下面的区间的 \(r\)。此时如果区间条件被满足了,上面一定大于下面。

那接下来就变成了一个二分图匹配问题:一边是 \(k\) 个区间,一边是 \(k\) 个点。一个区间可以匹配区间内的所有点。给定 \(k\) 个点中的 \(k-1\) 个,问剩下的那个点 \(d\) 在哪些位置能使二分图有完美匹配。

“哪些位置”,结合手玩,一个初步的猜测是一段前缀/后缀,但是自己造数据手玩,发现不一定。但是手玩又发现,好像合法的 \(d\) 都是一段区间。这确实是对的。

假设现在有一个 \(d_0\) 满足 \(d_0\) 是一个合法位置。我们考虑此时的完美匹配,一定包含了 \(d_0\)。

考虑从 \(d_0\) 开始走二分图的“交错路”:走一个匹配边,然后一个不匹配边,然后一个匹配边,然后一个不匹配边... 走偶数次。如果能走到 \(d_1\),那么将途经的匹配边删去,并把不匹配边匹配上,它依然是一个合法匹配且匹配数不变。那么它就变成了一个包含 \(d_1\) 的完美匹配。从而此时的 \(d_1\) 也是一个合法的 \(d\)。

由于这张二分图的性质,显然,经过“交错路”可以走到的点一定是一段区间。从而答案是一段区间,求出区间的 \(l,r\) 即可判断了。

尽管它确实是一段区间,但我们暂时没什么办法搞出这个 \(l,r\)。总之,我们有必要先想一个问题:假设我们已知所有的点,如何求完美匹配呢?显然不能暴力Dinic,存在一个贪心做法:将点从小到大排序,每个点选择包含它的 \(r\) 最小的区间匹配。将区间按 \(l\) 排序后,相当于取一段前缀(由于点不断变大,这段前缀也是不断变大的)里 \(r\) 最小的并删除。用 pq 维护即可。

我原本想了一个用线段树单点修改区间求min+二分大力维护的做法。显然我是sb。

这个贪心确实是对的,但它的问题在于扩展性不好。点中有一个变成了未知的点,那整个匹配都被打乱了。

我们也可以用这个做法求出 \(k-1\) 个点的匹配,然后剩下的那个区间是 \(d\) 的一段可行区间。但这不一定是 \(d\) 的整个可行区间,它可能只是一段子段

求出这个可行区间之后,在可行区间的左右分别二分好像是对的。虽然区间不能直接二分,但我们知道了区间中的一段,那么在这一段的左边一定是一段后缀满足,右边一定是一段前缀满足。

但这个做法是 \(\log^2\) 的,并且实现起来好像比较复杂,也许可以试试。

这里还有另一个做法就是,我先默认把 \(d\) 匹配到这里剩下的区间里,然后DFS走交错路,看能到哪些点。但是注意到左到右是区间连边,因此需要线段树优化建图。这就是我一开始写的做法。它 确实 是一个 \(\log\),但是它常数巨大且巨难写。

你也许会想到一个错误的贪心:按 \(l\) 排序,每次取区间内最小的点。

它为什么不对呢?这个贪心只便宜了 \(l\),如果下一个区间的 \(r\) 突然变小,那我们上一次取不太小的点,把最小的点留给这个区间,也许是更优的。

反例:区间 \([1,4],[2,3]\),点 \(3,4\)。这个做法会把 \(3\) 给 \([1,4]\),然后 \([2,3]\) 就没有匹配了。

我们发现它的扩展性很好(如果是对的),我们可以先对 \(k-1\) 个点做贪心。如果贪心的过程中区间里没有点了,就说明这个区间应该和 \(d\) 匹配。

它怎么改成对的呢?事实上按 \(r\) 从小到大排序就行了。可以证明,如果二分图存在完美匹配,那用这个办法一定可以取到一个。(证明思路就是假设当前如果取的不是区间里最小的,而是在后面取了这个最小的,这样有匹配,那么现在取最小的后面取大的那个也是可以的,不断这样交换就可以证明,如果存在一个完美匹配,一定可以用这种办法取到其中一个)

用这个策略不断的取,直到遍历当前区间时,区间里没点了,此时 \(d\) 就一定在这个区间里面了。由于我们是按 \(r\) 排序的,容易发现,此时这个区间的 \(r\) 就是最大的 \(d\) 。(很容易反证:如果 \(d\) 大于当前区间的 \(r\) 一定不行)。

一个值得注意的细节是,上述贪心过程中只能失配一次,这一次恰好用来确定 \(d\);如果失配了两次或以上,说明无解。

对称的,我们发现按 \(l\) 从大到小排序每次取区间里最大的也是对的。这样取一遍,区间里没点的时候,这个区间的 \(l\) 就是最小的 \(d\)。

然后这样就得到了合法的 \(d\) 的最大最小值,每次判给定的 \(d\) 是否在该区间里就行。注意中途做的时候判一下无解。

两次贪心用set即可简单维护,复杂度是小常数一个 \(\log\)。

标签:二分,匹配,一个,题解,CF1718D,一段,区间,贪心
来源: https://www.cnblogs.com/LightningUZ/p/16667963.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有