信息学奥赛一本通 1311:【例2.5】求逆序对

题目链接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1311

最坏情况下,逆序数对的数量为 ( n − 1 ) + ( n − 2 ) + . . . + 1 = n ( n − 1 ) 2 (n-1)+(n-2)+...+1=\frac{n(n-1)}{2} (n1)+(n2)+...+1=2n(n1),可能会爆掉 int。

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 100010;

int a[N], tmp[N];
ll res;

// 将[l1,r1]和[l2,r2]两个有序区间合并为一个有序区间
void Merge(int l1, int r1, int l2, int r2)
{
    int i = l1, j = l2, k = l1;
    while (i <= r1 && j <= r2)
    {
        if (a[i] > a[j])
        {
            res += r1 - i + 1;
            tmp[k++] = a[j++];
        }
        else
        {
            tmp[k++] = a[i++];
        }
    }
    
    while (i <= r1)
    {
        tmp[k++] = a[i++];
    }
    
    while (j <= r2)
    {
        tmp[k++] = a[j++];
    }
    
    for (int i = l1; i <= r2; i++)
    {
        a[i] = tmp[i];
    }
}

void MergeSort(int left, int right)
{
    // 若当前区间只有一个数或没有数,则直接return
    if (left >= right) return;
    
    // 将[left,right]划分为[left,mid]和[mid+1,right]两个子问题
    int mid = left + right >> 1;
    MergeSort(left, mid);
    MergeSort(mid + 1, right);
    
    // 将[left,mid]和[mid+1,right]两个有序区间合并为一个有序区间
    Merge(left, mid, mid + 1, right);
}

int main()
{
    int n;
    scanf("%d", &n);
    
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    
    MergeSort(0, n - 1);
    
    printf("%lld\n", res);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值