洛谷:P1908:逆序对


洛谷:P1908:逆序对

Table of Contents

题目

P1908:逆序对

分析

这道题延续前一道题P1177:排序(模板),用归并排序的特性快速计算逆序对(Inversions)。

所谓逆序对,就是在一个数组中,存在\(i\lt j, a[i]\gt a[j]\)。显然,经过排序后,这两个数字一定会交换位置,所以称为“逆序对”。

观察归并排序的过程:

  1. \(A[i]\le A[j]\),说明A[i]在前,拿出A[i]tmp[k]——这里的k指示tmp数组中下一个要处理的位置。A数组左边部分要看下一个(i++)。tmp数组的定位也要前进一次(k++)。
  2. \(A[i]\gt A[j]\),说明A[j]在前,拿出A[j]tmp[k]——这里的k指示tmp数组中下一个要处理的位置。A数组右边部分要看下一个(i++)。tmp数组的定位也要前进一次(k++)。

其中的情况2表明A[j]要提前,它和A[i]构成了一个逆序对。而且,此时A[i]后面的数也一定比A[j]大,一共有mid-i+1个。所以一旦出现这个情况,逆序对数量就要增加mid-i+1个:

    while (i <= mid && j <= r)
    {
        if (a[i] <= a[j])
        {
            tmp[k++] = a[i++];
        }
        else
        {
            // When we take element from right array, it forms inversions
            // with all remaining elements in left array
            inv_count += (mid - i + 1);
            tmp[k++] = a[j++];
        }
    }

特别注意:还需要递归加上左侧和右侧的逆序对数,再计算如上例中需要跨越边界的逆序对数。

答案

Solution

思考

用暴力算法当然可以,但时间复杂度是\(O(N^2)\),而归并排序的时间复杂度只有\(O(n log n)\),可以满足题目中要求\(1\le n\le 5×10^5\)的要求。

Previous Next