AcWing 107. 超快速排序(归并排序 + 逆序对)

在这个问题中,您必须分析特定的排序算法----超快速排序。

该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序。

对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 5 9

您的任务是确定超快速排序需要执行多少交换操作才能对给定的输入序列进行排序。

输入格式

输入包括一些测试用例。

每个测试用例的第一行输入整数n,代表该用例中输入序列的长度。

接下来n行每行输入一个整数aiai,代表用例中输入序列的具体数据,第i行的数据代表序列中第i个数。

当输入用例中包含的输入序列长度为0时,输入终止,该序列无需处理。

输出格式

对于每个需要处理的输入序列,输出一个整数op,代表对给定输入序列进行排序所需的最小交换操作数,每个整数占一行。

数据范围

0≤N<5000000≤N<500000,
0≤ai≤9999999990≤ai≤999999999

输入样例:

5
9
1
0
5
4
3
1
2
3
0

输出样例:

6
0

算法:归并排序 + 逆序对

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

const int maxn = 5e5+7;

ll arr[maxn], b[maxn];
ll ans;

void merge_sort(ll *arr, int l, int mid, int r) {
    int i = l, j = mid + 1;
    int k = 0;
    while(i <= mid || j <= r) {
        if(j > r || (i <= mid && arr[i] <= arr[j])) {
            b[k++] = arr[i++];
        } else {
            ans += mid - i + 1;
            b[k++] = arr[j++];
        }
    }
    for(int i = 0; i < k; i++) {
        arr[l + i] = b[i];
    }
}

void merge(ll *arr, int l, int r) {
    if(l < r) {
        int mid = (l + r) >> 1;
        merge(arr, l, mid);
        merge(arr, mid + 1, r);
        merge_sort(arr, l, mid, r);
    }
}

int main() {
    int n;
    while(scanf("%d", &n) && n) {
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &arr[i]);
        }
        ans = 0;
        merge(arr, 1, n);
        cout << ans << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/buhuiflydepig/p/11295765.html

时间: 2024-11-08 21:48:33

AcWing 107. 超快速排序(归并排序 + 逆序对)的相关文章

POJ 2299 Ultra-QuickSort(归并排序&#183;逆序对)

题意  给你一个数组求其中逆序对(i<j&&a[i]>a[j])的个数 我们来看一个归并排序的过程: 给定的数组为[2, 4, 5, 3, 1],二分后的数组分别为[2, 4, 5], [1, 3],假设我们已经完成了子过程,现在进行到该数组的"并"操作: a: [2, 4, 5] b: [1, 3] result:[1] 选取b数组的1 a: [2, 4, 5] b: [3] result:[1, 2] 选取a数组的2 a: [4, 5] b: [3] r

归并排序&amp;&amp;逆序对(codves1688,4163)

归并排序 归并排序采用的是分治的思想 1.划分问题:把序列分为元素个数尽量相等的两半 2.递归求解:把两半分别排序 3.合并问题:把两个有序的序列合并为一个 对于第三个问题,我们可以从两个序列中最小的元素开始比较,把较小的加入新的队列中,直到某个序列为空,把另外的一个序列直接加入,然后将原来的序列覆盖.其实很简单,下面看看模板代码 写得烂,不要在意(⊙o⊙)-: 这个就是归并排序(⊙o⊙)-,本人感觉很简单的,归并排序好像比sort,快排的复杂度低,也就是说快一点,是NlogN的复杂度.既然说了

POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组

http://poj.org/problem?id=2299 求逆序对最简单的绝对不会是树状数组,一定是归并排序(认真),不过树状数组会不会快一点呢?理论上应该是树状数组快一点(假如不进行离散化). #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set

【排序】归并排序+逆序对应用

1 void merge_sort(int *A, int x, int y, int *T) 2 {//x为左端点,y为右端点 3 // 4 if(y-x<=1) return ; 5 int m = x + (y-x)/2;//划分 6 int p = x, q = m, i = x; 7 //递归 8 merge_sort(A, x, m, T); 9 merge_sort(A, m, y, T); 10 //归并 11 while(p < m || q < y)//只要有一个序列

LG-P2804 神秘数字/LG-P1196 火柴排队 归并排序, 逆序对

P2804-神秘数字 题目描述(简化版) 有 n 个数,求这 n 个数中,有多少个连续的数的平均数大于某个给定的数 M? 注意:这个数可能会很大,请输出这个数对92084931取模的结果. 输入输出格式 输入格式: 共两行. 第一行为两个数 n 和 M. 第二行为 n 个数. 输出格式: 一行一个数,即问题的解对92084931取模的结果 输入输出样例 输入样例#1: 4 3 1 5 4 2 输出样例#1: 5 输入样例#2: 4 4 5 2 7 3 输出样例#2: 6 说明 [样例解释] ①对

利用归并排序法计算一个序列里有多少逆序对数(详细讲解)

前言 今天遇到求逆序对的问题,经过一番思索之后,特意来总结一下.因为也学习到了很多方法,以前自己一些百思不得其解的问题也有了解答. 正文 先上一个简单的问题: 分析:题目中说使用插入排序,也就是在排序过程中计算交换的次数,按照插入排序的原理,先定第一个,再定前两个的顺序,以此类推,只要交换了,我的次数就加一,但实际上,我们一直按照原始序列的顺序一直在往后走,所以(好,重点来了)我们要插入的就是前面比我大的数字前面的位置,也就是说,我需要交换的次数就是前面比我大的数字的个数,那么我考虑那就没必要进

归并排序 及拓展—逆序对

归并排序 时间复杂度 归并排序时间复杂度为O(NlogN) 似乎和快速排序差不多,但在有些特定的场合下,归并排序却能起到快速排序达不到的效果(如一年的联赛题,瑞士轮) 思路及实现 归并排序分为两个步骤,分.合: 分 的过程我们用二分的思路实现: 合 的过程时间复杂度可达到O(n); 分: 进行分治: 假设当前处理的区间为l~r; 实现: 过程定义:void merge_sort(int l,int r) merge_sort(l,l+r>>1); merge_sort(l+r>>1

codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)

题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 megabytes input standard input output standard output Mashmokh's boss, Bimokh, didn't like Mashmokh. So he fired him. Mashmokh decided to go to university

归并排序求逆序对

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