AcWing 788. 逆序对的数量

193 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

输入格式

第一行包含整数 n,表示数列的长度。

第二行包含 n 个整数,表示整个数列。

输出格式

输出一个整数,表示逆序对的个数。

数据范围

1≤n≤100000 数列中的元素的取值范围 [1,10^9]。

输入样例:

6
2 3 4 5 6 1

输出样例:

5

思路

归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。 归并排序 归并排序

如 设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11,;

逆序数为14;

在分治后的每一层合并中顺便求出逆序对数量

归并排序分治我们求的是从小到大的顺序

我们所求的逆序对恰好是逆序数量,与归并排序不谋而合。

Snipaste_2022-07-08_20-03-44.png

ac代码

c++

#include<iostream>
using namespace std;
typedef long long l1;
const int N =1000001;
int n;
int arr[N], tmp[N];
l1 merge_sort(int l,int r) {
    if(l>=r) return 0;
    int mid = l+r>>1;
    l1 res =merge_sort(l,mid)+merge_sort(mid+1,r);
    int k = 0,i=l,j= mid+1;
    while(i<=mid&&j<=r){
        if(arr[i]<=arr[j]) tmp[k++] = arr[i++];
        else {
            tmp[k++] = arr[j++];
            res+= mid-i+1;
        }
    }
    while(i<=mid) tmp[k++] = arr[i++];
    while(j<=r) tmp[k++] = arr[j++];
    for(int i = l,j=0;i<=r;i++,j++) arr[i] = tmp[j];
    return res;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    cout<<merge_sort(0,n-1)<<endl;
    return 0;
}

Java

import java.io.*;
public class Main{
    public static final int N = 100010;
    public static int[] temp = new int[N];
    public static void main(String args[]) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        String [] str = reader.readLine().split(" ");
        int[] arr = new int[n];
        for(int i = 0;i < n;i++) arr[i] = Integer.parseInt(str[i]);
        System.out.print(sort(arr,0,n - 1));
    }
    public static long sort(int [] arr,int l,int r){
        if(l >= r) return 0;
        int mid  = l + r >> 1;
        long res = sort(arr,l,mid) + sort(arr,mid + 1,r);
        int idx = 0,i = l,j = mid + 1;
        while(i <= mid && j <= r){
            if(arr[i] <= arr[j]) temp[idx++] = arr[i++];
            else{
                res += mid - i + 1;
                temp[idx++] = arr[j++];
            }
        }
        while(i <= mid) temp[idx++] = arr[i++];
        while(j <= r) temp[idx++] = arr[j++];
        for(i = l,j = 0;i <=  r;i++,j++) arr[i] = temp[j];
        return res;
    }
}