1164: 分治 逆序对
时间限制: 1 Sec 内存限制: 128 MB题目描述
给一列数a1,a2,...,an,求它的逆序对数,即有多少个有序对(i,j),使得i<j且ai>aj。n可以高达10^6。
输入
第一行输入整数N(2<=N<=10^6).
接下来一行N个正整数数分别是a1,a2,...,an(ai<=10^6)。
输出
输出一个数表示逆序对数。
样例输入
4
2 4 3 1
样例输出
4
重点体会分治思想!!
要熟练会写,有一道叫做手套的题就考了逆序对,一会贴上。
这里直接粘代码了
#include<iostream>
#include<cstdio>
using namespace std;
int n,a[2000001],i,c[2000001];
long long ans;
void x(int l,int r)
{
int mid=(l+r)/2,i,j,tmp;
if(r>l)
{
x(l,mid);
x(mid+1,r);
tmp=l;
for(i=l,j=mid+1;i<=mid&&j<=r;)
{
if(a[i]>a[j])
{
c[tmp++]=a[j++];
ans+=mid-i+1;
}
else c[tmp++]=a[i++];
}
if(i<=mid) for(;i<=mid;) c[tmp++]=a[i++];
if(j<=r) for(;j<=r;) c[tmp++]=a[j++];
for(i=l;i<=r;i++) a[i]=c[i];
}
}
int main()
{
cin>>n;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
x(1,n);
cout<<ans;
}
还有一份
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int A[9000010]={0},T[9000010]={0};
long long cnt=0;
void merge_sort(int x,int y)
{
if(y-x>=1){
int m=(y-x)/2+x;
int p=x,q=m+1,i=x;
merge_sort(x,m);
merge_sort(m+1,y);
while(p<=m||q<=y){
if(q>y||(p<=m&&A[p]<=A[q]))T[i++]=A[p++];
else {T[i++]=A[q++];cnt+=m+1-p;}
}
for(i=x;i<=y;i++)A[i]=T[i];
}
}
int main()
{
int n,m,ans=0,i,k;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&A[i]);
}
merge_sort(0,n-1);
printf("%lld",cnt);
}