[CF1698E] PermutationForces II 题解
与官方题解一样的解法,姑且发一篇题解,个人感觉思路非常自然,不需要什么思维上的火花。
首先考虑从题面入手来分析这道题目的做法,操作 \(n\) 次,每次选取值在 \([i,i+s]\) 区间内的两个点进行交换,最后使得 \(a\) 数组变为 \(b\) 数组,然后 \(b\) 数组中有一些位置待定,求可行解个数。
首先这种经典的计数题套路就是从判定入手,如果给定一个 \(b\) 数组,如何用一种通用的方法构造一组解或判定无解,注意到交换的方式有一些特殊,一个很直观的点就是值为 \(1\) 的点从始至终只能操作一次,这提醒我们在最劣情况下到第 \(i\) 次操作时前 \(i-1\) 个值应该已经归位,现在要解决值 \(i\) 的问题。
接下来就是解决本题的关键,以一个非常顺畅的思路,我们来到了判定是否有解的关键点——对于每个第 \(i\) 次交换能否使 \(i\) 回归原处,我们同样可以从 \(1\) 开始考虑。
首先我们可以将 \(b\) 数组排序,让 \(a\) 数组随着 \(b\) 数组排序,此时就变成把 \(a\) 数组变成一个顺序排列,即 \(1,2,\cdots,n\),这样的话我们第一次交换就是 \(a_1\) 和 \(1\),那么要求就是 \(a_1\le1+s\) 我们可以将这个特例大胆地普遍化成 \(a_i\le i+s\),我们可以试图证明这个东西:
首先这里的所有 \(a_i\) 是没交换前的 \(a_i\),且 \(a\) 数组已经随着 \(b\) 数组排序,那么我们分两种情况讨论:
- \(a_i>i\),当我们在做 \(i\) 时,\(a_i\) 还在原本的位置,则交换 \(i\) 与 \(a_i\),此时情况如上述所说,满足 \(a_i\le i+s\)。
- \(a_i<i\),此时 \(a_i\) 应该已经被交换过了,我们考虑 \(a_i\) 被交换成了 \(a_j\),那么应该满足 \(j<i\),那么上一次操作时的情况所需要满足的要求为 \(a_i\le j+s\),这两个不等式的交显然比 \(a_i\le i+s\) 更紧,所以满足要求。
上面证明了必要性,而充分性则是通过此要求构造解的过程,那么我们回到原问题,原问题就得到了转化,若 \(b\) 数组不排序,约束条件就为 \(a_i\le b_i+s\),因为我们是要构造 \(b_i\),所以进一步转化为 \(b_i\ge a_i-s\)。
那这个式子就非常好解决了,无解情况就是已经确定的 \(b\) 中有点不满足上述要求,否则我们将所有 \(a_i-s\) 取出,即将所有约束取出,再从紧到松排序,即先求出满足要求的情况数,再将情况数从小到大排序,再略加处理乘起来就好了。
实现上时间复杂度瓶颈是 sort
的 \(\mathcal O\left(n\log n\right)\),如果有闲心可以写计数排序优化到 \(\mathcal O\left(n\right)\),这里的代码是一切从简。