P1908 逆序对

P1908 逆序对

https://www.luogu.com.cn/problem/P1908

题目描述

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 a> aj且 i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

Update:数据已加强。

输入格式

第一行,一个数 n,表示序列中有 n个数。

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

输出格式

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

思路

题目数据很大,显然不能用O(n2)的冒泡做,所以选择效率更高的归并排序,本体相比普通的归并排序,只需要加上一条语句

ans += mid - i + 1;

逆序对的数量等于每一次发现 ai > aj 时 i 到 mid  的元素个数,因为 aj 比这些数都要小。

代码

#include<bits/stdc++.h>
using namespace std;
int a[500010];
int b[500010];
using ll = long long;
ll ans = 0;
void mergesort(int l, int r)
{
    if (l == r)
        return;
    int mid = (l + r) / 2;
    mergesort(l, mid);
    mergesort(mid + 1, r);
    int i = l;
    int j = mid + 1;
    int k = l;
    while (i <= mid && j <= r)
    {
        if (a[i] <= a[j])
            b[k++] = a[i++];
        else
        {
            b[k++] = a[j++];
            ans += mid - i + 1;
        }
    }
    while (i <= mid)
        b[k++] = a[i++];
    while (j <= r)
        b[k++] = a[j++];
    for (int i = l; i <= r; i++)
        a[i] = b[i];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    mergesort(1, n);
    cout << ans << "\n";
    return 0;
}

 

 

 

posted @ 2021-02-07 13:18  icey_z  阅读(211)  评论(0)    收藏  举报