怎么求逆序对的数量呢?一种特殊写法告诉你

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎么求逆序对的数量呢?一种特殊写法告诉你相关的知识,希望对你有一定的参考价值。

求逆序对的必备知识

我们要求逆序对,就要求前面的数比后面的数大的数对有多少个。

那么如果我们把每个数前面比它大的数有多少个求出来就可以了,答案就显而易见,就是每个数前面比它大的数的个数的和。

那么问题转化为求每个数前面比它大的数的个数。

怎么求呢?

我们考虑到可以用树状数组tr[]维护一个数组

先将原数组进行离散化,因为可能原数组的数据范围很大,数组空间不能开的很大。离散化之后原数组就变成了一个相对大小等级的数。(数小代表这个数值小相对其他数小)

然后每访问一个数,就把树状数组相对应等级的位置加一,代表该等级有一个数存在,然后i-sum(a[i])代表已经访问数的个数减去小于等于a[i]的数的个数(其实就是前面出现的大于a[i]的数的个数)

注意:树状数组存储的是数的大小等级(相对大小)

累加一下就好了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+5;
ll a[N],b[N],tr[N];
ll n;
void add(int p,int x)
{
    while(p<=n){tr[p]+=x;p+=p&-p;}
}
ll sum(int x)
{
    ll res = 0;
    while(x){res+=tr[x];x-=x&-x;}
    return res;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) {cin>>a[i];b[i]=a[i];}
    sort(b+1,b+1+n);//必须先排序才能去重
    int len = unique(b+1,b+1+n)-b-1;//去重
    for(int i=1;i<=n;i++)
        a[i] = lower_bound(b+1,b+1+len,a[i])-b;
    ll ans = 0;
    for(int i=1;i<=n;i++)
    {
        add(a[i],1);
        ans += i-sum(a[i]);
//        cout<<i-sum(a[i])<< "\\n";
    }
    cout<<ans<<'\\n';
    return 0;
}

以上是关于怎么求逆序对的数量呢?一种特殊写法告诉你的主要内容,如果未能解决你的问题,请参考以下文章

算法学习——利用归并排序求逆序对的数量

AcWing 788. 逆序对的数量

逆序对的数量(归并排序求解)

AcWing 788. 逆序对的数量

逆序对的数量

一道编程题:求逆序对的个数