首页 > 代码库 > POJ 2299 Ultra-QuickSort (求序列的逆序对数)

POJ 2299 Ultra-QuickSort (求序列的逆序对数)

题意:废话了一大堆就是要你去求一个序列冒泡排序所需的交换的次数。

思路:实际上是要你去求一个序列的逆序队数

看案例:

9 1 0 5 4
9后面比它小的的数有4个

1后面有1个

0后面没有

5后面1个

4后面没有

所以结果为4+1+0+1+0=6

所以逆序对的定义如果不清楚可以自己总结了

这道题说白了就是要你用归并排序求逆序对数。

下面是搜到某牛给的逆序对数的方法:

假设回溯到某一步,后面的两部分已经排好序(就是说当前需要归并的两个部分都是分别有序的),假设这两个序列为

序列a1:2 3 5 9  

序列a2:1 4 6 8

此时我们的目的就是要将a1和a2合并为一个序列。

由于在没排序前a2序列一定全部都是在a1序列之后的,当我们比较a2的1与a1的2时,发现1<2按照归并的思想就会先记录下a2的1,而这里实际上就是对冒泡排序的优化,冒泡是将a2的1依次与a1的9,5,3,2交换就需要4次,而归并却只有一次就完成了,要怎么去记录这个4呢,实际上由于1比2小而2后面还有4个数,也就是说那我的结果就必须要+4,也就是记录a1序列找到第一个比a2某一个大的数,他后面还余下的数的个数就是要交换的次数。

我的AC代码(按照刘汝佳书思路来的,大神别喷 ==):

#include<stdio.h>
#include<string.h>
int n,a[500005],b[500005];
__int64 sum;
void merge_sort(int x,int y)
{
    if(y-x>1)
    {
        int m=x+(y-x)/2;
        int p=x,q=m,i=x;
        merge_sort(x,m);
        merge_sort(m,y);
        while(p<m||q<y)
        {
            if(q>=y||(p<m&&a[p]<=a[q]))
                b[i++]=a[p++];
            else
            {
                sum+=m-p;
                b[i++]=a[q++];
            }
        }
        for(i=x;i<y;i++)a[i]=b[i];
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sum=0;
        merge_sort(0,n);
        printf("%I64d\n",sum);
    }
    return 0;
}