我的第一篇题解

题目描述

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2,那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。

思路

求逆序数对,即统计序列中每个元素的左边大于该元素的个数。

ans+=getsum(n)-getsum(a[i]);

因为会出现数据大于n的情况,所以想到离散化。

算法

树状数组、离散化、归并排序等。

离散化

离散化:把任何不在合适区间的数转化为不超过元素个数的数。 例如:{2022,8,29}->{3,1,2}

temp[i].val记录原数

temp[i].pos记录原数的位置

struct node{
	int val,pos;
}temp[maxn];

a[]为离散化好的数组

	sort(temp,temp+n,cmp);
	for(int i=0;i<n;i++)
	{
		if(i!=0&&temp[i].val==temp[i-1].val)
			a[temp[i].pos]=a[temp[i-1].pos];
		else
			a[temp[i].pos]=i+1;
	}

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x) ((x)&(-x))

const int maxn=100005;
int n;
int a[maxn],c[maxn];
struct node{
	int val,pos;
}temp[maxn];
bool cmp(node a,node b)
{
	return a.val<b.val;
}
void update(int x)
{
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]++;
}
ll getsum(int x)
{
	ll sum=0;
	for(int i=x;i>0;i-=lowbit(i))
		sum+=c[i];
	return sum;
}
int main()
{
	cin>>n;
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		cin>>temp[i].val;
		temp[i].pos=i;	
	}
	sort(temp,temp+n,cmp);
	for(int i=0;i<n;i++)
	{
		if(i!=0&&temp[i].val==temp[i-1].val)
			a[temp[i].pos]=a[temp[i-1].pos];
		else
			a[temp[i].pos]=i+1;
	}
	for(int i=0;i<n;i++)
	{
		update(a[i]);
		ans+=getsum(n)-getsum(a[i]);
	}
	cout<<ans<<endl;
	return 0;
}