数据结构 归并排序-逆序数对

逆序对是指数列a[1],a[2],a[3]…中的任意两个数a[i],a[j] (i<j),如果a[i]>a[j],那么我们就说这两个数构成了一个逆序对。

而归并排序的合并两个排列的过程中

会将右边的有序序列的元素依次插入前面的 有序序列

如(3 7 12)   ( 5 6 8)

将5 插入  (3 7 12) 中

因为后面有序 所以 假设   5和左边全部元素构成逆序对  所以有mid+1

而左边序列又有start1 个数比5 小  所以 逆序数就是  mid+1-start1

这样就能大大缩减 计算逆序数对的时间。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[500005],b[500005];
long long ans;
void merge(int left,int mid,int right)
{
    int start1=left,start2=mid+1;
    int num=left;
    int i;
    while(start1<=mid&&start2<=right)
    {
        if(a[start1]>a[start2])
        {
            ans=ans+mid-start1+1;
            b[num++]=a[start2++];
        }
        else
            b[num++]=a[start1++];
    }
    while(start1<=mid)
            b[num++]=a[start1++];
    while(start2<=right)
            b[num++]=a[start2++];
    for(i=left; i<=right; i++)
        a[i]=b[i];
    return;
}
void mergesort(int left,int right)
{
    int mid=(left+right)/2;
    if(left<right)
    {
        mergesort(left,mid);
        mergesort(mid+1,right);
        merge(left,mid,right);
    }
    return;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        ans=0;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        mergesort(1,n);
        printf("%lld\n",ans);
    }
    return 0;
}
时间: 2024-08-10 11:40:25

数据结构 归并排序-逆序数对的相关文章

AcWing:108. 奇数码问题(归并排序 + 逆序数)

你一定玩过八数码游戏,它实际上是在一个3×3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3×3的网格中. 例如: 5 2 8 1 3 _ 4 6 7 在游戏过程中,可以把空格与其上.下.左.右四个方向之一的数字交换(如果存在). 例如在上例中,空格可与左.上.下面的数字交换,分别变成: 5 2 8 5 2 _ 5 2 8 1 _ 3 1 3 8 1 3 7 4 6 7 4 6 7 4 6 _ 奇数码游戏是它的一个扩展,在一个nn×nn的网格中进行,其中nn为奇数,1个空格和1

Inversion(HDU_4911) 归并排序+逆序数对

Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 3171    Accepted Submission(s): 1154 Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers f

Frosh Week(HDU_3743)归并排序+逆序数对

Frosh Week Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2772    Accepted Submission(s): 923 Problem Description During Frosh Week, students play various fun games to get to know each other a

归并排序(逆序数问题)详解

微信公众号:bigsai 前言 在排序中,我们可能大部分更熟悉冒泡排序.快排之类.对归并排序可能比较陌生.然而事实上归并排序也是一种稳定的排序,时间复杂度为O(nlogn). 归并排序是基于分治进行归并的,有二路归并和多路归并.我们这里只讲二路归并并且日常用的基本是二路归并.并且归并排序的实现方式有递归形式和非递归形式.要注意其中的区分(思想上没有大的区别,只是划分上会有区分后面会对比). 并且归并排序很重要的一个应用是求序列中的逆序数个数.当然逆序数也可以用树状数组完成,这里就不介绍了. 归并

归并排序 逆序数

很好理解: int n,a[500010],c[500010]; long long ans; void msort(int L,int R) { if(L==R)return ; int mid=(L+R)>>1; msort(L,mid); msort(mid+1,R); int i=L,k=L,j=mid+1; while(i<=mid&&j<=R) if(a[i]<=a[j]) c[k++]=a[i++]; else c[k++]=a[j++],ans

求逆序数

第一部分:题目 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5)每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所

求逆序数的三种数据结构比较

本文比较 数状数组,线段树,还有一种unnamed的数状结构,在求逆序数中的运行效率. 给定数组a,如果有i, j, i < j且a[i] > a[j],我们称之为一个逆序(反序),求逆序数即找出这样的i,j对的数目.如果通过交换相邻元素来对数组排序,那么逆序数正好是最少的交换次数.长度为n的排列,其逆序数的期望是n(n-1)/4,方差是n(2n+5)(n-1)/72.逆序数的平均数可以大概视为n^2/4,标准差大概视为(1/6)n^(3/2). 经典的求逆序数的算法可以由归并排序给出,但是在

poj1804(归并排序求逆序数)

逆序数,也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序.一个排列中所有逆序总数叫做这个排列的逆序数. 我们移动元素的次数转化为,假如对每个数da[i]来说前面比他大的数的数目为c[i]的话,那么移动元素总次数就应该是c[0]+c[1]+--+c[n-1],就是数列的逆序数. 一般解决有两种思路. 1.归并排序,归并排的话一定是最好的方案,主观上想

归并排序_逆序数

归并排序求逆序数 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.一个排列中所有逆序总数叫做这个排列的逆序数.也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序.一个排列中所有逆序总数叫做这个排列的逆序数. 1 #include<cstdio> 2 #in