最近太颓了……听 zbs2006 说有好玩的题就来做一做。
给定两个序列 \(a\),\(b\),现在要将 \(b\) 插入 \(a\) 中,没有顺序和位置的要求,使最终的逆序对数尽可能少,求个数。
解析
我们容易得到 \(b\) 在插入时一定是有序的,否则交换两个数一定更优。感性理解一下就是在两个数之间并且值域也在两个数之间的数会对这对数造成贡献。
事实上想到这里就有一个简单易懂的做法:从左往右贪心插入,用线段树维护 \(\min\) 及其位置然后二分一下,每个数贪心插入最小位置就做完了。但我没有这么写。
接下来就是我永远想不到的部分了:对 \(b\) 分治,每次贪心插入 \(b_{mid}\),然后两边分别递归下去。接下来我们讨论正确性。
对于一个数 \(x\),记比它大的数为 +1
,相等的为 0
,否则为 -1
。则对逆序对的贡献就是 \(x\) 之前的 +1
数减去 \(x\) 之后的 -1
数。
显然如果我们每次都将 \(x\) 后移一位,则贡献量至多改变 \(1\),且对于所有空隙,总贡献最小的位置总是构成若干个 0
的区间。
考虑比 \(x\) 小的数 \(x_1\) 的插入位置,注意到对于 \(x_1\) 而言,所有的 0
都会变成 +1
,所以再取 \(x\) 的最优位置总会不优于 \(x\) 第一个最优位置。
然后考虑如下的递归 \(\operatorname{solve}(l_1,r_1,l_2,r_2)\) 过程:
- 如果 \(l_2>r_2\) 返回;
- 令 \(mid = \left\lfloor{l_2+r_2\over 2}\right\rfloor\),找到 \(mid\) 在 \([l_1,r_1]\) 的局部最优解(易证这里就是全局最优解)位置 \(p\)。
- 递归求解 \(\operatorname{solve}(l_1,p,l_2,mid-1)\) 和 \(\operatorname{solve}(p,r_1,mid+1,r_2)\)。
插入完成后再求解逆序对数就做完了。复杂度容易证明是 \(\mathcal{O}((n+m)\log m)\)。
注意事项
求逆序对数组要开两倍。