NOI杂题选做
注:这篇文章按照题目年份来排序。由于本人代码较为松散,放上代码会占用较多空间,因此选择放测评链接。
2018
D1T2 冒泡排序
由于这是这篇博文的第一个记录的题,所以写的比较详细。
好像我们在去年暑假考NOI套题的时候就做过这道题,只不过当时我 $ \text{next_permutation} $ 了而已。
现在回头来看这道题,还是非常巧妙的。
首先,我们需要找到什么样的排列能满足其交换次数达到下界,这也应该是我们第一个想到的切入点。
那么我们应该想到,满足交换次数达到下界的排列必然不可能含有一个长度 \(\geq 3\) 的下降子序列,因为如果含有一个长度 \(\geq3\) 的下降子序列,那么第二个元素在与第一个元素交换完后,必然会与第三个元素交换造成“走远路”的情况,那么是肯定不能满足交换次数到达下界的条件的。
那么是不是所有不含长度 \(\geq 3\) 的下降子序列的排列都能让交换次数达到下界呢?答案是肯定的。至于证明,我个人认为题解区里面\(\text{shadowwice}\)的证明给的简单明了,可以作参考(我也是看那个才看懂的)。
那么现在先不考虑字典序的限制,答案如何计算呢?
我们不妨这样想,设当前已经放置的最大值为 \(j\),那么我们定义“限制元素”表示还没有填的值小于 \(j\) 的元素。
显然,限制元素必须按顺序填入,否则即非法。
如果我们在这一个位置上填上第 \(k\) 个非限制元素,那么非限制元素的数量将会减少 \(k\) 个。如果填上限制元素,那么将不会有变化。
我们可以设 \(f_{i,j}\) 表示当前剩下 \(i\) 个元素,其中有 \(j\) 个是非限制元素。 显然能得到下式:
可以发现,这个东西其实就是两个组合数相减。
那么我们在预处理阶乘及阶乘逆的情况下容易 \(O(1)\) 求出 \(f_{x, y}\) 。
其实, \(f_{n, n}\) 就是卡特兰数 \(C(n)\) 。
然后我们再来考虑有限制的情况。 设当前做到第 \(i\) 位, 还剩余的非限制元素数目为 \(cnt\), 在它前面比他小的数有 \(b\) 个, 后面有 \(c\) 个比它大。
我们可以让 \(cnt\) 和 \(c\) 取个min, 因为填入这一位后的 \(cnt\) 必然不大于 \(c\) 。
首先我们考虑这一位填入的 \(p_i > a_i\) 时的情况,如果此时 \(cnt = 0\) ,那么意味着后面的元素必然只能按顺序排列,这个排列的字典序是严格不大于给定排列的(此时前面填入的元素完全相同),那么就可以break了。
否则, 答案就会加上 \(f_{n - i + 1, cnt - 1}\) ,这个可以 \(O(1)\) 计算。
那么再考虑 \(p_i= a_i\) 的情况。首先,如果 \(c\) 更新了 \(cnt\) 的值,说明这一位一定是填入了一个非限制元素,所以必然合法。
另一种情况是, \(a_i\) 是当前未填入的非限制元素的最小值,即 \(a_i = b + 1\) 这个时候也是合法的。
否则,就可以直接 \(\text{break}\) 了。
瓶颈是求出 \(b\) 与 \(c\) ,这个可以使用树状数组进行维护。 时间复杂度 \(O(n \log n)\) 。

浙公网安备 33010602011771号