求逆序数
时间限制:
2000 ms | 内存限制:
65535 KB
难度:
5
-
描述
-
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。
比如 1 3 2 的逆序数就是1。
-
输入
-
第一行输入一个整数T表示测试数据的组数(1<=T<=5)
每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)
随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。
数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。
输出
- 输出该数列的逆序数 样例输入
-
2 2 1 1 3 1 3 2
样例输出
-
0 1
来源
第一种 归并排序应用
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MAX=1000010;
long long array[MAX];
long long temp[MAX];
long long count;
void Merge(int l,int mid,int r)//(2)“合并”——将划分后的序列段两两合并后排序。
{
int i=l;// i是第一段序列的下标
int j=mid+1; // j是第二段序列的下标
int k=l;
while(i<=mid&&j<=r)// 同时开始扫描第一段和第二段序列,直到有一个扫描结束
{// 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
if(array[i]>array[j])//第一段大于第二段
{
temp[k++]=array[j++];
count+=mid-i+1;//移动距离,也就是逆序数的值
}
else if() //第二段大于等于第一段 合理不用改变
{
temp[k++]=array[i++];
}
}
while(i<=mid) // 若第一段序列还没扫描完,将其全部复制到合并序列
temp[k++]=array[i++];
while(j<=r) // 若第二段序列还没扫描完,将其全部复制到合并序列
temp[k++]=array[j++];
for(i=l;i<=r;++i) // 将合并序列复制到原始序列中
array[i]=temp[i];
}
void Merge_sort(int l,int r)//(1)“分解”——将序列每次折半划分。
{
if(l<r)
{
int mid=(l+r)>>1;//右移一位 相当于除2
Merge_sort(l,mid);//递归
Merge_sort(mid+1,r);
Merge(l,mid,r);//左区间,
}
}
int main()
{
int t,i,j,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%lld",&array[i]);
count=0;
Merge_sort(0,n-1);
printf("%lld\n",count);
}
return 0;
}
第二种 树状数组
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define Max 1000005
using namespace std;
int c[Max];//树状数组
int n;
/*
建立一个结构体包含t和pos, t就是输入的数,pos表示输入的顺序。然后按照t从小到大排序,如果t相等,那么就按照pos排序。
如果没有逆序的话,肯定pos是跟i(表示拍好后的顺序)一直一样的,如果有逆序数,那么有的i和pos是不一样的。
所以,利用树状数组的特性,我们可以简单的算出逆序数的个数。
*/
struct Node{
int t;
int pos;
}A[Max];
bool cmp(Node a,Node b)
{
if(a.t==b.t)
return a.pos<b.pos;
return a.t<b.t;
}
int lowbit(int n)
{
return n&(-n);
}
void add(int i)
{
while(i<=n)
{
c[i]++;//可能有重复元素,所以用++,不用=1;
i+=lowbit(i);
}
}
int sum(int i)//返回数组到i的所有值
{
int sum=0;
while(i>0)
{
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
int T,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&A[i].t);//值
A[i].pos=i;//位置
}
memset(c,0,sizeof(c));
stable_sort(A+1,A+n+1,cmp);
/*
stable_sort和sort的区别在于 前者作排序可以使原来的"相同"的值在序列中的相对位置不变
如 1 4 6 7 4' (4 和 4'值相等,加上' 表示是2个不同的元素)
那么stable_sort能保证排序完, 4仍然在4'前,即输出1 4 4' 6 7;但是sort没有这个功能,不能保证排序的稳定
*/
long long ans=0;
for(i=1;i<=n;i++)
{
add(A[i].pos);
ans+=i-sum(A[i].pos);
}
printf("%lld\n",ans);
}
return 0;
}