求逆序对

问题:

问题描述:

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为 “逆序对” 的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aj
​且 i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

输入格式:

第一行,一个数 nn,表示序列中有 nn 个数。 第二行 nn 个数,表示给定的序列。序列中每个数字不超10^9。

输出格式:

输出序列中逆序对的数目。

输入样例:

6
5 4 2 6 3 1

输出样例:

11

说明/提示:

对于所有数据,n <= 5* 10^5

思考:

求解思路是递归,分而治之,利用了归并排序。在进行二路归并的时候对逆序对进行统计。
如图所示:

在每一次递归排序的时候统计逆序对的数量。

代码:

divide()函数的目的在于把序列划分,然后调用sort()函数进行排序。

#include <iostream>
using namespace std;

long long s = 0;
void divide(int *a, int left, int right);
void merge(int *a, int b1, int e1, int b2, int e2); //归并排序
int main()
{
    int n;
    cin >> n;
    int a[500010];
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    divide(a, 1, n);
    cout << s << endl;
}

void divide(int *a, int left, int right)
{
    int mid = (left + right) / 2;

    if (left >= right)
    {
        // do nothing
    }
    else
    {
        divide(a, left, mid);
        divide(a, mid + 1, right);
        merge(a, left, mid, mid + 1, right);
    }
}

void merge(int *a, int b1, int e1, int b2, int e2)
{
    int i, j, k;
    i = b2, j = b1, k = 0;
    long long temp[e2 - b1 + 2]; //辅助数组
    while (i <= e2 && j <= e1)   //归并排序
    {
        if (a[i] < a[j])
        {
            s += (e1 - j + 1);
            temp[k] = a[i];
            i++;
        }
        else
        {
            temp[k] = a[j];
            j++;
        }
        k++;
    }
    if (i <= e2)
        for (; i <= e2; i++, k++)
            temp[k] = a[i];
    if (j <= e2)
        for (; j <= e1; j++, k++)
            temp[k] = a[j];
    k--;
    // 把排序后的数据在复制回a数组中
    for (i = b1, j = 0; j <= k && i <= e2; j++, i++)
        a[i] = temp[j];
}
posted @ 2022-03-17 22:15  请去看诡秘之主  阅读(51)  评论(0)    收藏  举报