这是腾讯的一道笔试题,网上没找到特别好的题解,就写了一下。(免得我自己也忘了
做这题前首先要了解普通的逆序对
逆序对_力扣leetcode-cn.com题面:
作为程序员的小Q,他的数列和其他人的不太一样,他有逆序对_腾讯笔试题_牛客网www.nowcoder.com个数。
老板问了小Q一共次,每次给出一个整数(1<=i<=m), 要求小Q把这些数每分为一组,然后把每组进行翻转,小Q想知道每次操作后整个序列中的逆序对个数是多少呢? 例如:
对于序列1 3 4 2,逆序对有(4, 2),(3, 2),总数量为2。
翻转之后为2 4 3 1,逆序对有(2, 1),(4, 3), (4, 1), (3, 1),总数量为4。
输入描述:
第一行一个整数(0n20)
第二行个整数
第三行一个整数(m)
第四行个整数(0n)
输出描述:行每行一个数表示答案
逆序对是一个比较经典的问题,但是腾讯的这题麻烦在这个坏老板刁难程序员,每次都要你区间翻转之后再询问,然后就变成在线问题了。如果你每次都反转完之后再用经典的方法(归并、树状数组)求一遍逆序对是很慢的,复杂度O(
),直接爆炸。
我们这样定义长度为
的序列的逆序对数量cnt[i]:将其对分为两个长度为
的序列A, B,把一个数对<p,q>(p
A,q
B, 且p>q)记为一个逆序对,逆序对数量就是这样的<p,q>的数量。(这其实就是归并排序在某一深度的递归中统计逆序对时所做的事情
我们可以得出下面的规律:
- 对于一个数字的序列,其逆序对数量 = 非相等对数量 - 顺序对数量。而一个区间的反转,就是其顺序对数量和逆序对数量互换。
- 一个长度
的序列,可以分为两个长度的子序列,子序列的翻转是不影响长度序列的逆序对数量的。
- 数列的总逆序对数量 =
这道题由于共有
个数,数的分组也是按照
个数一组分的,正好和归并排序时的对半划分吻合。
所以我们可以只进行一遍归并排序,维护一个cnt数组,cnt[i]记录以长度为
分组的各组逆序对之和。
对于长度为
的序列,其非相等对数量 =
相等对数可以在归并排序的时候统计。
每次的翻转数
只对cnt[k] (1
k
qi)有影响。
代码:
#include