排序计数类题目小结
考虑到每次出哒哒哒操作,最少多少次操作使数组有序这一类题我都错的很惨,小小地总结一下
1.交换相邻位置的点->求逆序对(火柴排队,10.30noip模拟赛T1),有效的操作一定使得逆序对减少一个
2.交换任意位置->转化为置换(10.30noip模拟赛T1),置换内交换只需要置换中点个数次
3.每次可以把一个数扔到最前面->(HDU5500,noip模拟赛11.12T1)官方题解:
把这题的模型简化一下,有一个1→n的排列形成的数列,我们要用最少的操作次数把这个数列排序,每次操作都是把一个数放到整个数列的最前面。 首先我们可以注意到每个数最多只会被操作一次。因为假如有一个数被往前拿了两次,显然第一次的操作是没有意义的。 然后能发现一定先操作大的数,再操作小的数。因为假如先把小的数放前面去了,再把大的数放前面去,小的数就又在大的数后面了,小的数必定还得再操作一次,然而操作两次是不划算的。
到这里,对于19的数据范围,我们有一个很暴力的做法,2^n2n枚举要操作哪些数,这些操作按数的大小从大往小的顺序,模拟一下,然后检查一下最后的序列是否有序,复杂度O(n*2^n)O(n∗2n)。
我们很快又能发现,假如操作了大小等于kk的数,那么所有小于kk的数也都得操作了。所以我们不用2^n枚举,直接mm从11开始从小到大枚举,表示要操作前mm小的数,然后模拟,验证,这样复杂度为O(n^2)O(n2)。
不过其实mm也是不用枚举的。 首先可以发现最大的数nn是不用操作的(其他数操作好了,数"nn"自然就在最后面了)。 于是我们先找到最大的数"nn"的位置,从这个位置往前找,直到找到(n-1)(n−1)。假如找到头也没找到(n-1)(n−1),那么数"(n-1)(n−1)"需要操作,而一旦操作了(n-1)(n−1),根据前面结论,总共就需要(n-1)(n−1)次操作了;假如找到了(n-1),那么数"(n-1)(n−1)"也不需要操作(和数"nn"不需要操作一个道理)。 同理,我们接着从(n-1)(n−1)的位置往前找(n-2)(n−2),再从(n-2)(n−2)的位置往前找(n-3)(n−3)...假如数kk找不到了,那么就至少需要kk次操作。这种做法的复杂度是O(n)O(n)的
个人理解:每次把后面最大的往前扔,就不会导致出现有点扔两次,并且这样一定能够扔完...
4.每次可以和他后面(不一定相邻)的数交换->统计比后面的最小值大的数的个数即可,原因...不知道//再想想?(noip模拟赛11.14T1)
之后还有的话再写//还有脑洞也可以再写T T