链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=117
花了一晚上和上午的时间终于调试出来了,一开始没有考虑到存在相等数字的情况~~
这里有必要对归并排序进行总结。分为分治三步法
1.划分问题:把序列分成元素个数尽量相等的两半
2.递归求解:把两半元素分别排序
3.合并问题:把两个有序表合并成一个
此题求逆序中的第二步就是统计i,j均在左边或者均在右边的逆序对个数,合并问题则是统计i在左边,但j在右边的逆序对个数。
这里采取的策略可以这样理解,合并过程中,对于右边的元素按照从小到大的序列排序出列时,每出一个,左边存在几个元素,这表示该元素相对于左边有几个逆序(这里不包括自身右边的元素)
AC代码:
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
long long sum;
int a[1000008];
void Merge(int a[],int first,int mid,int last,int b[])
{
int i,j,k,m,t=0,s1;
i=first;
j=mid;
k=mid+1;
m=last;
s1=mid-first+1;
while(i<=j&&k<=m)
{
if(a[i]<=a[k])
b[t++]=a[i++];
else
{
sum=sum+s1-i+first; //注意这里,i的值是相对于first的,所以要加上first
b[t++]=a[k++];
}
}
while(i<=j)
b[t++]=a[i++];
while(k<=m)
b[t++]=a[k++];
for(k=0;k<t;++k) //利用b辅助数组进行排序
a[first+k]=b[k];
}
void Sort(int a[],int first,int last,int b[])
{
if(first<last)
{
int mid=(first+last)/2;
Sort(a,first,mid,b);
Sort(a,mid+1,last,b);
Merge(a,first,mid,last,b);
}
}
int main()
{
int test,n,i;
scanf("%d",&test);
while(test--)
{
sum=0;
memset(a,0,sizeof(a));
scanf("%d",&n);
for(i=0;i<n;++i)
scanf("%d",&a[i]);
int *p=new int[n+1];
Sort(a,0,n-1,p);
printf("%lld\n",sum); //sum必须为long long类型
}
}