牛客2.8 逆序数 归并排序(代码修改)

第8节 逆序数
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。
输入描述:
第一行有一个整数n(1 <= n <= 100000), 然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。

输出描述:
输出这个序列中的逆序数
示例1
输入
5
4 5 1 3 2
输出
7


思路:
1 利用归并排序的过程计算逆序对个数
当右指针指向的数比左指针小的时候,从左指针p1 到 mid 的数 都能与 右指针 p2 形成逆序对, 个数为 mid-p1+1

2 cot要开long long
n的范围为1e5,当a数组降序时,逆序对个数规模可以达到n^2,超过int


#include
using namespace std;
const int N=1e7+10;
typedef long long ll;
ll cot=0;
int a[N],b[N];
void merge(int l,int mid,int r)
{
	int p1=l,p2=mid+1;
	for(int i=l;i<=r;i++)//存下归并后的数组 
	{
		//if((p2>r)||a[p1]<=a[p2])//这地方有问题
		//当数组为 1 2 3 4 时 ,第4轮时,p1指向4,p2指向3,就会跳到else 里
		//改成下面
		if(p2>r||(p1<=mid&&a[p1]<a[p2]))
		{
			b[i]=a[p1];
			p1++;
		} 
		else//逆序的情况 
		{
			b[i]=a[p2];
			p2++; 
			cot+=mid-p1+1;//累加记录逆序对的个数 
		}
	}
	for(int i=l;i<=r;i++)
	{
		a[i]=b[i];//将临时数组b[i]中的数转移到原数组a中 
	} 
}

void erfen(int l,int r)
{
	int mid=(l+r)>>1;//除以2 
	if(l<r)
	{
		erfen(l,mid);
		erfen(mid+1,r);
	}
	merge(l,mid,r);
}

int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	erfen(1,n);
	cout<<cot<<endl;
//	for(int i=1;i<=n;i++) cout<
	return 0;
 } 


你可能感兴趣的:(c++)