【上海交大oj】逆序数对(归并排序)

3021. 逆序数对

Description

给你一个数组,求该数组的逆序数

Input Format

输入文件第一行包含一个自然数N,N个数 接下来有N行,表示a[0],a[1]...a[n - 1]

Output Format

输出文件仅有一行包含一个整数,表示该数组的逆序数

Sample Input

3
575085724
344369358
808884464

Sample Output

1==============================================所谓逆序数,就是一个数列中的元素,比它大并且排在它前面的数的个数,然后对每个元素逆序数求和就是答案。如果直接做的话,对每个数都要扫描它前面的所有数,复杂度为n^2,因此可以用归并排序的思想。所谓归并排序,有点类似分治法,比如4,1,3,2,首先把序列分为两半并调用归并函数(递归直到只有一个元素)分别得到两个有序子序列,然后对这两个子序列进行归并.归并过程是这样的:
对两个子序列同时从左到右扫描,选取较小值加入序列。对于1,4和2,3,选取顺序是为:1->2->3->4.
那么怎么统计逆序数对呢?举个例子,当扫描到3时,对于它自身所在子序列:在它以前的元素肯定比它小,不计,在它后面的元素在因为在对这个子序列排序时已经计算过了(原来是3,2,子序列分别为3和2,那么扫描到2的时候会对3统计)也不用计。对于这个时刻和它进行比较的子序列:此时和它比较的元素以前的肯定比它小(如1,4中的元素4以前的元素(1)),不计,只要计算和它比较的元素本身及之后的元素就行了。因此,等到排完序(nlogn)后,逆序数对也就求出来了。具体代码:

 1 #include <iostream>
 2 using namespace std;
 3 long long n,count = 0;
 4 long long arr[100000],a[100000],b[100000];//要计算的序列和两个子序列
 5 void mergesort(int , int);
 6 void merge(int, int, int);//归并过程
 7 int main(){
 8     int n;
 9
10     cin>>n;
11     for (int i = 0; i < n;++i) cin>>arr[i];
12     mergesort(0,n-1);
13     cout<<count;
14
15     return 0;
16 }
17 void merge(int l,int m,int r){
18     if (l==r) return;
19     int len1 = m - l + 1,p = 0,q = 0;
20     int len2 = r - m;
21     for (int i = 0;i < len1;++i) a[i] = arr[i+l];
22     for (int i = 0;i < len2;++i) b[i] = arr[m+i+1];
23     a[len1] = 1000000000000000000;
24     b[len2] = 1000000000000000000;
25     for (int i = l;i <= r;++i){
26         if (a[p] <= b[q]) arr[i] = a[p++];
27         else{
28             count += m - p -l + 1;//计算逆序数对
29             arr[i] = b[q++];
30         }
31     }
32 }
33 void mergesort(int l,int r){
34     if (l>=r) return;
35     int m = (l+r)/2;
36     mergesort(l,m);
37     mergesort(m+1,r);
38     merge(l,m,r);
39 }

				
时间: 2024-10-12 23:23:59

【上海交大oj】逆序数对(归并排序)的相关文章

1.7 逆序数与归并排序[inversion pairs by merge sort]

[本文链接] http://www.cnblogs.com/hellogiser/p/inversion-pairs-by-merge-sort.html [题目] 编程之美1.7光影切割问题可以进一步将问题转化为求逆序数问题. [分析] 求解逆序对问题与MergeSort类似,只需要对MergeSort稍作修改即可实现.MergeSort是采用分治法的思想,若需要排序A[p...r],则可以对半分成A[p...q]和A[q...r],然后将这有序的两部分Merge,而Merge的过程为Θ(n)

求逆序数(归并排序)

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5) 每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000) 随后的一行共有N个整

求逆序数_归并排序

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5)每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)随后的一行共有N个整数A

ACM_小明滚出去?(归并排序求逆序数)

小明滚出去? Time Limit: 2000/1000ms (Java/Others) Problem Description: 老师:"小明,写一个排序算法": 小明: void mysort(int a[],int n) //n为数组a的元素个数 { int i,j; for(j=0;j< n-1;j++) for(i=0;i< n-1;i++) { if(a[i] >a[i+1])//数组元素大小按升序排列 { swap(a[i],a[i+1]);//交换 }

拼图游戏中逆序数的实现的三种方式

一.定义 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.如2431中,21,43,41,31是逆序,逆序数是4. 二.计算方法 逆序数的计算方法主要有直接计算,归并和树状数组三种,下面将一一介绍. 2.1 直接计算 即根据定义用枚举的方法求逆序数.对于数列中的每一个数a[i],遍历数列中的数a[j] (其中j < i),若a[i] < a[j],则逆序数加1,这样就能统计出该数列的逆序数总和. 该方

《程序设计与算法(二)算法基础》《第五周 分治》求排列的逆序数 11

011:求排列的逆序数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务. 对于不同的排名结果可以用逆序来评价它们之间的差异.考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序. 一个排列含有逆序的个数称为这个排

nyist oj 117 求逆序数 (归并排序&amp;&amp;树状数组)

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5) 每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000) 随后的一行共有N个整

归并排序_逆序数

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

poj 2299 Ultra-QuickSort 归并排序求逆序数对

题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题思路: 根据冒泡排序的特点,我们可知,本题只需要统计每一个数的逆序数(如果有i<j,存在a[i] > a[j],则称a[i]与 a[j]为逆序数对),输出所有的数的逆序数的和用普通排序一定会超时,但是比较快的排序,像快排又无法统计 交换次数,这里就很好地体现了归并排序的优点.典型的利用归并排序求逆