NUC_TeamTEST_C && POJ2299(只有归并)


Ultra-QuickSort

Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 42627   Accepted: 15507

Description

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 
9 1 0 5 4 ,
Ultra-QuickSort produces the output 
0 1 4 5 9 .
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

Source

Waterloo local 2005.02.05

这道题就是通过求逆序数的和,来求出序列所有的交换次数。用冒泡排序直接会TLE(相当于暴力了),

这道题有3种解法,树状数组、线段树、归并排序(O(N*lgN))

其中归并排序的写法应该是最简单的,树状数组、线段树要用到离散化,博客后续还会跟上

归并写法,其实归并写法,自己并不是很熟练,推介大牛博客

http://blog.163.com/zhaohai_1988/blog/static/20951008520127321239701/

大牛代码真心漂亮!!中间核心,就是学大牛写的

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define LL long long              //LL 代替 long long 的写法 中间数据会超出  int
 5 using namespace std;
 6
 7 const int max_size = 500010;
 8
 9 int arry[max_size], tmp_arry[max_size];
10
11 LL Merge(int *arr, LL beg, LL mid, LL end, int *tmp_arr)
12 {
13     memcpy(tmp_arr+beg, arr+beg, sizeof(int)*(end-beg+1));
14     LL i = beg;
15     LL j = mid + 1;
16     LL k = beg;
17     LL inversion = 0;
18     while(i <= mid && j <= end)
19     {
20         if(tmp_arr[i] <= tmp_arr[j])   ///如果合并逆序数的时候,前边小于等于后边,就不用记录逆序数的值
21         {
22             arr[k++] = tmp_arr[i++];
23         }else{
24             arr[k++] = tmp_arr[j++];   ///如果不是,则要记录逆序数的值
25             inversion += (mid - i + 1);///简单画下就能看出
26         }
27     }
28
29     while(i <= mid)                    ///把没有并入arr数组的数并入
30
31     {
32         arr[k++] = tmp_arr[i++];
33     }
34     while(j <= end)
35     {
36         arr[k++] = tmp_arr[j++];
37     }
38     return inversion;
39 }
40
41 LL MergeInversion(int *arr, LL beg, LL end, int *tmp_arr)
42 {
43     LL inversions = 0;
44     if(beg < end)
45     {
46         LL mid = (beg + end) >> 1;
47         inversions += MergeInversion(arr, beg, mid, tmp_arr);    ///分成两段分别进行记录,递归的进行下去,找逆序数和
48         inversions += MergeInversion(arr, mid+1, end, tmp_arr);
49         inversions += Merge(arr, beg, mid, end, tmp_arr);
50     }
51     return inversions;
52 }
53
54 int main()
55 {
56     LL n;
57
58     while(cin >> n)
59     {
60         if(n == 0)
61             break;
62         for(int i = 0; i < n; ++i)
63             scanf("%d", &arry[i]);
64         memcpy(tmp_arry, arry, sizeof(int)*n);
65         cout << MergeInversion(arry, 0, n-1, tmp_arry) << endl;
66     }
67     return 0;
68 }
时间: 2024-11-03 01:27:35

NUC_TeamTEST_C && POJ2299(只有归并)的相关文章

POJ2299 求逆序对总数 归并算法解决

逆序对 比如 3 2 1   3之前的数没有比它大的(或者说前面没有数了),所以没有逆序对 2之前的数有3比它大 所以有逆序对+1 1之前的数有 3 2 比它大 所以有逆序对+2 所以 3 2 1 序列 的 总的逆序对为3对 ----- 在归并算法中 合并两个已经排序好的序列时 是从两个序列的首个位置开始进行比较 合并方法传入的参数为:first mid(分界下标) last 第一个序列下标:first ~ mid 第二个序列下标:mid + 1 ~ last 1.如果a[i] <= a[j]

poj2299解题报告(归并排序求逆序数)

POJ 2299,题目链接http://poj.org/problem?id=2299 题意: 给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列. 思路: 其实就是求逆序数,那么直接向到的就是冒泡了,交换一次,记录一次即可.但是n的范围达到50W,冒泡O(n^2)的复杂度铁定超时. 然后...发现曾经微软有一道笔试题类似就是求逆序数的,对,没错,用归并. 例:合并两个序列(1,3,5)(2,4,6),新序列第二个元素是2,那么它和它前面的3.5形成了逆序数对

3002 石子归并 3

时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=3000) 第二行n个整数w1,w2...wn  (wi <= 3000) 输出描述 Outpu

LeetCode OJ:Merge k Sorted Lists(归并k个链表)

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 类似于归并2个链表,暴力一点的方法就是,每取出一个list就与以前的list归并返回merge后list,知道所有list merge完成. 但是可惜,这样做会TLE.贴下代码先: 1 /** 2 * Definition for singly-linked list. 3 * struct List

排序算法之归并算法

/* 本例拟在实现排序算法的归并算法,归并算法遵循分治法的思想 归并算法: 归并算法主要用来合并两个已经排好序的序列.用Merge(A,p,q,r)来实现合并, 其中A代表数组,A[p,q]和A[q+1,r]A的两个子数组,且两个数组都已经排好序,归并算法 就是将这两个子数组合并成一个排好序的数组并替代当前的数组A[p,r]. */ public class Merge { public static void main(String[] args) { int[] a = {1,2,3,4,5

K-th Number 线段树(归并树)+二分查找

K-th Number 题意:给定一个包含n个不同数的数列a1, a2, ..., an 和m个三元组表示的查询.对于每个查询(i, j, k), 输出ai, ai+1, ... ,aj的升序排列中第k个数 . 题解:用线段树,每个节点维护一个区间并且保证内部升序,对于每次查询x,返回该区间小于x的数的个数.就这样不断二分,直到找到x为止. 线段树(归并树)+二分查找 1 #include <iostream> 2 #include <cstdio> 3 #include <

LeetCode-Sort List,链表排序(插入和归并),时间复杂度O(n^2) and O(nlgn)

题目: 1.Sort a linked list using insertion sort 2.Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 3.Sort a linked list in O(n log n) time using constant space

C++ 模板实现败者树,进行多路归并

项目需要实现一个败者树,今天研究了一下,附上实现代码. 几点说明: 1. 败者树思想及实现参考这里:http://www.cnblogs.com/benjamin-t/p/3325401.html 2. 多路归并中的“多路”的容器使用的是C语言数组 + 数组长度的实现(即 const ContainerType* ways, size_t num ),而没有用STL中的容器,这是因为项目需要如此,日后再改成STL容器: 3. _losers 存储下标,用的是 int 类型,还需要修改.程序中其他

线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

为什么线段树可以求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:可以从头开始往后找比当前元素小的值,也可以从后往前找比当前元素大的值,有几个逆序数就是几. 线段树就是应用从后往前找较大值得个数.(一边更新一边查) 当前个数是 n = 10 元素   9  5   3 9先加入线段树,T[9]+=1:查从T[9]到T[10]比9大的值,没有sum = 0: 5 加入线段树,T[5] += 1,查从T[5]到T[10]比5大的值,有一个9,sum +=1: 3