P1966 火柴排队
https://www.luogu.com.cn/problem/P1966
其实题目意思就是给你两列数,通过交换相邻两个数的位置,上下两个对应的数会有一个差的平方,假设就叫k吧,每两个对应的数就会有个k,最后要求所有k的总和要最小,问最少需要交换多少次?
分析:
想要最后的和小,那么每一个k都要尽量小(废话)。遵循大对大,小对小的原则(好像叫方差…)。其实我们在乎的不是这个数本身的数值,而是它在数列中的排名。就比如A数列的最大的,对应B数列中最大的,A数列中最小的,对应B数列中最小的…以此类推。所以这就要用到离散化的思想。
思路:
让我们来简单分析一下样例2:
A: 1 3 4 2
然后我们将它按大小编个码:
编码:1# 3# 4# 2#
A : 1 3 4 2
code: 1# 3# 4# 2#
//这里code表示的是排名,
//例如1是最小的排第一位,所以是1#;
//2是第二小的排第二位,所以是2#
然后我们对第二组数动手术
A : 1 3 4 2
code: 1# 3# 4# 2#
//这里code表示的是排名,例如1是最小的排第一位,所以是1#;2是第二小的排第二位,所以是2#
B: 1 7 2 4
下标: 1# 2# 3# 4#
hope: 1# 4# 2# 3#
//下标就是下标(后面求逆序对有用)
//hope是我们希望排成的样子,就是跟上面的1 3 4 2对应起来:(大对大,小对小)
//首先对A数组的1#,我们要拿最小的数去对,B数组中最小的数是B[1]=1,它的下标是1,所以填1#
//再举个例子,比如我们要对A的4#(排行老4,最大的),我们要拿B数组最大的去对,找到B[2]=7
//是最大的,那么记录下它的下标就是2#
//最后我们所hope的下标顺序就是1 4 2 3。
然后我们就要考虑调换的问题。本来B数组的排列方式是1 2 3 4(下标),现在我们所hope的是1 4 2 3,这该怎么算呢?
其实我们不妨反过来想,与其想怎么从1 2 3 4变成 1 4 2 3,不如想怎么从1 4 2 3变成1 2 3 4这就变成了一个逆序对的事,只要求1 4 2 3中的逆序对个数就是调换次数。
逆序对:
所谓逆序对就是“反过来”。例如1 3不是,但3 1就是逆序对,(字面意思)
逆序对的一般解法就是打勾数组+前缀和,反过来统计就行了(但这题可以优化)我先来解释一下常规做法:
求 1 4 2 3的逆序对
0 1 2 3 4