CF771D

Portal

被 tzc 拉来做这题,然后他好像不太会,然而我自己 AC 了((

至于为什么要单独写一篇题解呢,因为这题一个重要结论是我 baidu 出来的(

感谢 tzc 让我会了这样一个普遍性结论(


注意到这个字符串里面只分三种字符:( exttt V)( exttt K),和两个都不是的。这启示我们弄个三维 DP 分别记录三种字符的个数。然后因为相邻字符对有限制,所以还要再弄一维记录当前最后一个字符是啥。那么多项式算法的雏形就出来了。

然后一个难点在于:将一个字符串重新排列得到另一个字符串,那么如何算原串到新串的最小交换次数。

  • 「这题难点就在如何算移动次数」
  • 「告诉你个秘密:一个数列冒泡排序的次数等于逆序对数」(没错这个就是我 bfs 出来的,当年 NOIOL R1T2 好像也是这个结论,然后我当时不会,百撕不得其姐,后面有时间补吧。这个证明其实非常好证,就是说有逆序对那么一定会有相邻逆序对(这个是显然的吧,反证即可),那么任意一次有效交换都恰好消掉一个逆序对(就是此相邻逆序对),那不证完了么)
  • 「然后转化一下就可以算这题的移动次数了(」

至于如何转化,我们考虑将它的重排看成一个置换 (a),那么最小交换次数显然就是 (a) 的逆序对数(这看似是一个挺常用的套路)。但是本题中字符串里可能有相同元素,那怎么知道它重排后到底哪个是原先的哪个位置呢?这也很简单,只需要贪心的,对于每个字符,在新串中把所有等于它的位置的 (a) 值按照原串里面所有它的位置从小到大顺着排即可,这样显然可以控制逆序对最少化。

然后这个就是 DP 可以算的了。我们每次枚举上一个字符转移,然后算上当前位置作为逆序对中右边那个的贡献,显然只跟之前的三种字符的个数有关。具体怎么算我们可以在三种字符的位置序列里面二分,但也可以预处理,做到三方复杂度。

code

珍爱生命,远离抄袭!
原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-cf771d.html