逆序对

给定一个1-N的排列A1, A2, ... AN,如果Ai和Aj满足i < j且Ai > Aj,我们就称(Ai, Aj)是一个逆序对。

求A1, A2 ... AN中所有逆序对的数目。

Input

第一行包含一个整数N。

第二行包含N个两两不同整数A1, A2, ... AN。(1 <= Ai <= N)

对于60%的数据 1 <= N <= 1000

对于100%的数据 1 <= N <= 100000

Output

一个整数代表答案

Sample Input

5
3 2 4 5 1

Sample Output

5

暴力O(n^2) ,超时,所以要用归并排序,还有一种树状排序,后面在学;

#include<bits/stdc++.h>
#define sf scanf
#define scf(x) scanf("%d",&x)
#define scff(x,y) scanf("%d%d",&x,&y)
#define scfff(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define vi vector<int>
#define mp make_pair
#define pf printf
#define prf(x) printf("%d\n",x)
#define mm(x,b) memset((x),(b),sizeof(x))
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
const double eps=1e-6;
const double pi=acos(-1.0);
const int inf=0xfffffff;
const int N=1e5+7;
ll ans;//答案 
void merge(int a[],int l,int mid,int r)
{
	int b[r-l+1];				//开辅助空间存原来的数,在把数字排好放回原数组 
	int pos1=l,pos2=mid+1;		//两个指针位置 
	rep(i,l,r+1) b[i-l]=a[i];	//复制 
	rep(i,l,r+1)
	{
		if(pos1>mid) a[i]=b[pos2++-l];
		else if(pos2>r) a[i]=b[pos1++-l];//以上两种是如果有一边已经放完了 
		else					//如果还没放完 
		{
			if(b[pos1-l]>b[pos2-l])	 //右边小,把右边的数字插入 
			{//如果这是左边的数大于右边,那么符合逆序对的条件要加上去
				ans+=mid-pos1+1;//求逆序对的时候加上这个就可以,不用就不加 
				a[i]=b[pos2++-l];
			}else			//左边小,把左边的数字放进去 
				a[i]=b[pos1++-l];
		}
	}
}
void msort(int a[],int l,int r) 
{
	if(l==r) return;	//如果只有一个数字就回 
	int mid=(l+r)>>1;
	msort(a,l,mid);
	msort(a,mid+1,r);//分开排序 
	merge(a,l,mid,r);//组合再一起,顺便求逆序对的数量 
}
int main()
{
	int a[N],n;
	while(~sf("%d",&n))
	{
		rep(i,0,n)
			scf(a[i]);
		ans=0;
		msort(a,0,n-1);
		pf("%lld\n",ans);
	}
}


posted @ 2018-07-26 21:40  一无所知小白龙  阅读(318)  评论(0编辑  收藏  举报