hihoCoder_二分·归并排序之逆序对

一.题目

题目1 : 二分·归并排序之逆序对

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

在上一回、上上回以及上上上回里我们知道Nettle在玩《艦これ》。经过了一番苦战之后,Nettle又获得了的很多很多的船。

这一天Nettle在检查自己的舰队列表:

我们可以看到,船默认排序是以等级为参数。但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况。比如上图中77级的飞龙改二火力就小于55级的夕立改二。

现在Nettle将按照等级高低的顺序给出所有船的火力值,请你计算出一共有多少对船满足上面提到的这种情况。

提示:火力高才是猛!

输入

第1行:1个整数N。N表示舰船数量, 1≤N≤100,000

第2行:N个整数,第i个数表示等级第i低的船的火力值a[i],1≤a[i]≤2^31-1。

输出

第1行:一个整数,表示有多少对船满足“A船比B船等级高,但是A船火力低于B船”。

样例输入
10
1559614248 709366232 500801802 128741032 1669935692 1993231896 369000208 381379206 962247088 237855491
样例输出
27

二.解题技巧

根据题目的提示,这道题可以使用二分归并排序来对数组进行排序的同时,统计逆序数的个数。具体做法是将两个子问题进行二分归并排序后得到的逆序数加上将子问题进行归并的时候,后面一半的元素移动的位置来得到最终的逆序数。

三.实现代码

#include <iostream>

#include <vector>

using namespace std;

long long Merge(vector<int>::iterator BeginIte, int Number)

{

if (Number < 2)

{

return 0;

}

int Mid = Number / 2;

int IndexFirst = 0;

int IndexSecond = Mid;

vector<int> TmpArray;

long long Count = 0;

int Index = 0;

while ((IndexFirst < Mid) && (IndexSecond < Number))

{

int TmpFirst = *(BeginIte + IndexFirst);

int TmpSecond = *(BeginIte + IndexSecond);

if (TmpFirst > TmpSecond)

{

TmpArray.push_back(TmpSecond);

Count += IndexSecond++ - Index++;

}

else

{

TmpArray.push_back(TmpFirst);

IndexFirst++;

Index++;

}

}

while (IndexFirst < Mid)

{

TmpArray.push_back(*(BeginIte + IndexFirst++));

}

while (IndexSecond < Number)

{

TmpArray.push_back(*(BeginIte + IndexSecond++));

}

// copy the array back

for (int Index = 0; Index < Number; Index++)

{

*(BeginIte++) = TmpArray[Index];

}

return Count;

}

long long MergeSort(vector<int>::iterator BeginIte, int Number)

{

if (Number < 2)

{

return 0;

}

int Mid = Number / 2;

long long Count = 0;

Count += MergeSort(BeginIte, Mid);

Count += MergeSort(BeginIte + Mid, Number - Mid);

Count += Merge(BeginIte, Number);

return Count;

}

int main()

{

int Number = 0;

cin >> Number;

int Index = 0;

vector<int> Array;

while (Index++ < Number)

{

int Tmp = 0;

cin >> Tmp;

Array.push_back(Tmp);

}

cout << MergeSort(Array.begin(), Number) << endl;

//    for (int Index = 0; Index < Number; Index++)

//    {

//        cout << Array[Index] << endl;

//    }

// cout << "The result is " << Count << endl;

return 0;

}

四.体会

这道题让我长了见识,我记得我以前的做法是先使用STL里面的sort函数对数组进行排序,然后根据排序后的数组的元素的下标与相同元素在原来数组里面的下标的关系,来计算逆序对的个数(也就是逆序数)。这种方法不仅需要进行排序的时间O(nlgn),在使用hash_table的时候,还需要O(n)的时间来判断元素在排序后的数组的下标与原来数组的下标的关系,稍微有些复杂。

这道题使用二分归并排序在进行排序的同时,也递归计算量数组中的逆序对的个数,是一种很实用的方法。这种方法主要是基于数组中的逆序对的个数等于子问题中存在的逆序对的个数加上归并过程中存在的逆序对的个数。归并过程中存在的逆序对的个数等于后面一半的元素移动到正确位置时需要移动的位数的和。

版权所有,欢迎转载,转载请注明出处,谢谢

时间: 2024-12-27 15:55:31

hihoCoder_二分·归并排序之逆序对的相关文章

二分&#183;归并排序之逆序对 算法讲解和题目

题目: #1141 : 二分·归并排序之逆序对 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ>.经过了一番苦战之后,Nettle又获得了的很多很多的船.这一天Nettle在检查自己的舰队列表:我们可以看到,船默认排序是以等级为参数.但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况.比如上图中77级的飞龙改二火力就小于55级的夕立改二.现在Nett

#1141 : 二分&#183;归并排序之逆序对(归并排序)

#1141 : 二分·归并排序之逆序对 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ>.经过了一番苦战之后,Nettle又获得了的很多很多的船. 这一天Nettle在检查自己的舰队列表: [list.png] 我们可以看到,船默认排序是以等级为参数.但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况.比如上图中77级的飞龙改二火力就小于55级的夕立

[hiho]二分&#183;归并排序之逆序对

描述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ>.经过了一番苦战之后,Nettle又获得了的很多很多的船.这一天Nettle在检查自己的舰队列表:我们可以看到,船默认排序是以等级为参数.但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况.比如上图中77级的飞龙改二火力就小于55级的夕立改二.现在Nettle将按照等级高低的顺序给出所有船的火力值,请你计算出一共有多少对船满足上面提到的这种情况. 提示:火力高才是猛! 输入

hihoCoder#1141 二分&#183;归并排序之逆序对

原题地址 又是一道WA成狗的题,最后发现原来是结果溢出了.. 代码: 1 #include <iostream> 2 #include <cstring> 3 4 using namespace std; 5 6 #define MAX_N 100008 7 8 int N; 9 long long a[MAX_N]; 10 long long b[MAX_N]; 11 12 long long count(int l, int r) { 13 if (l >= r) 14

【hiho39】二分&#183;归并排序之逆序对

最近申请了微软的暑假实习,4号就要在线笔试了,在线测试系统用的是http://hihocoder.com/,今天试手做了一道题. [题目] 原题链接:http://hihocoder.com/contest/hiho39/problem/1 输入 第1行:1个整数N,表示数组长度. 第2行:N个整数,表示数组的元素a[i],1≤a[i]≤2^31-1. 输出 第1行:1个整数,表示有多少对元素满足a[i]>a[j],i<j. 样例输入 10 1559614248 709366232 50080

二分·归并排序之逆序对

http://hihocoder.com/contest/hiho39/problems java.util.*; Main {     = ;     mergSort(List<Long> a, l, r) {         mid;         (l < r) {             mid = (l + r) / ;             (a,l, mid);             (a, mid + , r);            List<Long&g

[HiHoCoder]二分&#183;归并排序之逆序对

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ>.经过了一番苦战之后,Nettle又获得了的很多很多的船. 这一天Nettle在检查自己的舰队列表: 我们可以看到,船默认排序是以等级为参数.但实际上一个船的火力值和等级的关系并不大,所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况.比如上图中77级的飞龙改二火力就小于55级的夕立改二. 现在Nettle将按照等级高低的顺序给出所有船的火力值

归并排序+归并排序求逆序对(例题P1908)

归并排序(merge sort) 顾名思义,这是一种排序算法,时间复杂度为O(nlogn),时间复杂度上和快排一样 归并排序是分治思想的应用,我们先将n个数不断地二分,最后得到n个长度为1的区间,显然,这n个小区间都是单调的,随后合并相邻的两个区间,得到n/2个单增(减)的区间,随后我们继续合并相邻的两个区间,得到n/4个单增(减)的区间.... 每次合并操作的总时间复杂度为O(n),logn次合并用时O(logn),故总时间复杂度为O(nlogn) 合并操作比较好理解,就像下图这样二分区间即可

归并排序求逆序对

归并排序求逆序对 by mps [1]什么是逆序对? 对于一个数列需要按从小到大排序,如果有ai,aj且满足ai>aj和i<j则ai,aj为一组逆序对 [2]如何求逆序对? 我们发现,我们可以暴力枚举i,j,然后逐一判断并累加答案即可,时间复杂度O(N2)        但是对于数据量大一点的题目,只有不断地TLE了→_→ [3]归并排序求逆序对 逆序对的定义(见[1])是一组本应该有序的序列中的逆序对,那么我们就想到了排序,但由于是要22匹配,我们又想到了归并排序 归并排序大致内容如下: 将