【2024信友队 - 提高模考】Day 6 套题3 T2:交换
题面
小 B 忘记做作业了!昨天的作业是对 $n$ 个不同的数从小到大进行排序,然而小 B 作业本上的数依旧是乱序的。老师正在检查作业,还要检查 $m$ 个同学就要到达小 B 这里了,检查每个同学的时间都是 $t/m+10^{-100}$ 秒( $t$ 为本题时限)。
小 B 知道,自己的作业如果做的太差,一定能得到和老师谈心的好机会。不过好在,老师已经把答案写在了黑板上,因此这时小 B 的作业可以看成一个长度为 $n$ 的排列 $a_1,a_2,\dots,a_n$ ,$a_i$ 表示小 B 作业中第 $i$ 位的数在 $n$ 个数中是第 $a_i$ 小。而且老师也公布了评分的标准:按字典序评分。也就是说对于两种排序方式,分别为 $p_1,p_2,…,p_n$ 和 $q_1,q_2,…,q_n$ ,设 $x_0 = min\{x|p_x ≠q_x\}$ ,那么第 $x_0$ 位较小的那个排序方式可以获得更高的分数。
由于数字很多,抄已经来不及了。于是小 B 打算使用交换的方式,在老师检查到每个同学的时候,小 B 都会观察出一个区间 $[l,r]$ ,在这个区间内交换两个数不会被老师察觉。小 B 眼疾手快,他观察老师和交换两个数的用时总和是 $10^{-100}$秒。小 B 希望每一次交换,他都能选取交换后得分最高,即字典序最小的交换方式。然而他并不能在 $t$ 秒中找出答案,于是他向同桌的你求助,希望你能告诉他每一步该如何交换。
对于部分数据:
性质 A :逆序对数小于等于 $100$ 。
性质 B :排列和询问随机
思路
题目大意:给定一个排列,每次给定一个区间,交换区间内的两个数使得排列字典序最小,询问交换的位置,多次询问。
算法1
按照题意模拟,枚举交换位置并比较。时间复杂度 $O(mn²)$。期望得分 $20$ 分。
算法 2
不难发现给定区间之外的位置对每个询问的答案无影响,所以每次的问题就是取出一个子段,问这个子段怎样交换一次字典序最小。根据字典序定义,我们需要找到最小的位置满足通过交换可以使这个位置变小,也就是说这个位置不是后缀最小值,因此从后往前取最小值,找出可以变小的位置中最靠前的一个。最后与把这个位置与这个位置之后的最小值交换就是最优的了。时间复杂度 $O(mm)$ 。期望得分 $40-50$ 分。
算法3
对于性质 A 可以用 $\tt set$ 暴力找出这些逆序对。因为每次交换的时候一定会使逆序对减少,所以对于每个询问,枚举哪些逆序对在区间中,选择最优的交换,并更新减少的逆序对。时间复杂度 $O(n\log n+100m)$ 结合前面的算法,期望得分 $55-60$ 分。
算法 4
对于性质 B 可以发现每个区间第一个可以交换变优的位置会很靠前。直接暴力枚举前几位看一下是不是能交换,用线段树维护区间最小值。应该可以取得不错的效果。结合前面的算法,期望得分 $65-70$ 分。
正解
问题在于如何求出第一个能变小的位置。可以找出这一段区间从开头开始的最长的连续上升段,那么交换的一定是连续上升段内和连续上升段后的数字。可以求出连续上升段之后的最小值,然后找到连续上升段中第一个比这个最小值大的位置,交换这两个位置就是最优的。
求连续上升段可以为每个位置维护一个标记,表示这个位置是否比下一个位置大。使用线段树二分查找第一个有标记的位置就能找到最长连续上升段。线段树维护最小值很简单。最后查询连续上升段中比一个数大的最小位置,这个可以维护区间的最大值,同样二分查找即可。
时间复杂度 $O(n\log n)$ 。
代码
1 |
|