求排列的逆序数

Posted kindleheart

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求排列的逆序数相关的知识,希望对你有一定的参考价值。

考虑1,2,…,n (n <= 100000)的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。
一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个 逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。
现给定1,2,…,n的一个排列,求它的逆序数。

笨办法:O(n2)

分治O(nlogn):
1) 将数组分成两半,分别求出左半边的逆序数和右半边的逆序数
2) 再算有多少逆序是由左半边取一个数和右半边取一个数构成(要求O(n)实 现)

由归并排序改进得到,加上计算逆序的步骤

MergeSortAndCount: 归并排序并计算逆序数

代码:

#include<iostream>
using namespace std;
#define N 100000 + 5
int n; 
int a[N];
int b[N];
int ans = 0;
void merge(int L, int R) {
    int mid = (L + R) / 2;
    int l = L;
    int r = mid+1;
    int count = 0;
    while(l <= mid && r <= R) {
        if(a[l] < a[r]) {
            b[count++] = a[r++];    
        } else {
            b[count++] = a[l++];
            ans += R - r + 1;
        }
    }
    while(l <= mid) b[count++] = a[l++];
    while(r <= R) b[count++] = a[r++];
    for(int i = L; i <= R; i++) a[i] = b[i-L];
}
void MergeSortAndCount(int L, int R) {
    if(L < R) {
        int mid = (L + R) / 2;
        MergeSortAndCount(L, mid);
        MergeSortAndCount(mid + 1, R);
        merge(L, R);
    }
}
int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    MergeSortAndCount(0, n-1);
    printf("%d
", ans);
    return 0;
}

 





以上是关于求排列的逆序数的主要内容,如果未能解决你的问题,请参考以下文章

树状数组求逆序对

求排列的逆序数(分治)

求排列的逆序数

逆序对问题---求逆序数

求排列的逆序数之树状数组

树状数组求逆序数