逆序对的数量-归并排序解法

0 阅读1分钟

题目:

image.png

题解:

一种高效的计算逆序对的方法是使用修改后的归并排序算法。基本思想是将数组分割为较小的子数组,递归地对它们进行排序,然后在合并过程中计算逆序对。

归并排序步骤:将数组递归地分割为两半,直到每个子数组只有一个元素。然后,将子数组按照排序顺序合并回来,同时在合并过程中计算逆序对。

合并过程中计算逆序对:在合并两个已排序的子数组时,如果发现逆序对(即 arr[i] > arr[j]),则将逆序对的数量递增为第一个子数组中剩余的元素数量(即 (mid - i + 1),其中 mid 是合并的子数组的中间索引)。

这是因为在合并过程中,如果左边的子数组元素 arr[i] 大于右边的子数组元素 arr[j],则 arr[i] 大于右边子数组中的所有元素,形成逆序对。

代码:

#include<iostream>
using namespace std;

const int N = 1e6+10;

int n;
int q[N],tmp[N];

long long merge_sort(int q[],int l,int r)
{
    if(l>=r) return 0;
    int mid = (l+r)/2;
    
    long long result = 0;
    result = merge_sort(q,l,mid) + merge_sort(q,mid+1,r);
    
    int i=l,j=mid+1,k=0;
    while(i<=mid&&j<=r)
    {
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else{
            tmp[k++]=q[j++];
            result+=mid-i+1;
        }
    }
    
    while(i<=mid) tmp[k++]=q[i++];
    while(j<=r) tmp[k++]=q[j++];
    
    for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
    
    return result;
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    cout<<merge_sort(q,0,n-1);
    return 0;
}