逆序对
给定一个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);
}
}