归并排序找逆序数

题意:

bobo has a sequence a 1,a 2,…,a n. He is allowed to swap two adjacent numbers for no more than k times. 
Find the minimum number of inversions after his swaps. 
Note: The number of inversions is the number of pair (i,j) where 1≤i<j≤n and a i>a j.

Input

The input consists of several tests. For each tests: 
The first line contains 2 integers n,k (1≤n≤10 5,0≤k≤10 9). The second line contains n integers a 1,a 2,…,a n (0≤a i≤10 9).

Output

For each tests: 
A single integer denotes the minimum number of inversions.

Sample Input

3 1

2 2 1

3 0

2 2 1

Sample Output

1

2

分析:归并排序+贪心

这里有个k要注意,就是可以交换相邻数字的位置,使得逆序数最小,那么我们肯定是把最小的数字往前换,这样我们算逆序数就只要把原来的逆序数算出来再减去可以交换的次数就好了,当然如果算出来是负数我们就让它直接等于零吧!

代码:

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn =100000+5;
 4 const int Q = 50000 + 5;
 5 int arr[maxn];
 6 int lef[Q], rig[Q];
 7 long long  ans;
 8 int lef_size;
 9 int rig_size;
10 void Merger(int arr[], int L, int M, int R)
11 {                                                     //归并整个数组
12     int i, j, k;
13     lef_size = M - L;
14     rig_size = R - M;
15     for (i = L; i < M; i++)
16     {
17         lef[i - L] = arr[i];                          //放在左边的数组
18     }
19     for (i = M; i < R; i++)
20     {
21         rig[i - M] = arr[i];                            //放在右边的数组
22     }
23     i = 0; j = 0; k = L;
24     while (i < lef_size&&j < rig_size)
25     {
26         if (lef[i] <= rig[j])                         //左边数组小于右边数组
27         {
28             arr[k] = lef[i];                           //把左边数组的数放进整合数组中
29             i++;                                      //左数组下标加加
30             k++;                                      //整合数组下标加加
31             ans += j;                                  //逆序数加加(相当于在找i与下一个i之间插进去的数字,只要有数字插队,就表示
32                                                         //左边(也可以说前面)大于了右边的数字(后面),所以加J,可能有点不好理解,
33                                                            //自行脑补吧!)
34         }
35         else
36         {
37             arr[k] = rig[j];
38             j++;
39             k++;
40         }
41     }
42     while (i < lef_size)
43     {                                             //没有放完的左边的数
44
45         arr[k] = lef[i];
46         i++;
47         k++;
48         ans += j;
49
50
51     }
52     while (j < rig_size)
53     {
54         arr[k] = rig[j];
55         j++;
56         k++;
57
58     }
59 }
60 void Mergersort(int arr[], int L, int R)
61 {
62     if (L + 1<R)                           //归并排序
63     {
64         int M = (L + R) / 2;
65         Mergersort(arr, L, M);
66         Mergersort(arr, M, R);
67         Merger(arr, L, M, R);
68     }
69 }
70 int main()
71 {
72     int n;
73     long long k;
74     while (cin >> n>>k)
75     {
76         ans = 0;
77         for (int m = 0; m < n; m++)
78             cin >> arr[m];
79         Mergersort(arr, 0, n);
80         if (ans - k > 0)
81             cout << ans - k << endl;
82         else
83             cout << "0" << endl;
84     }
85     return 0;
86 }
时间: 2024-10-24 23:34:30

归并排序找逆序数的相关文章

归并排序_逆序数

归并排序求逆序数 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.一个排列中所有逆序总数叫做这个排列的逆序数.也就是说,对于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]为逆序数对),输出所有的数的逆序数的和用普通排序一定会超时,但是比较快的排序,像快排又无法统计 交换次数,这里就很好地体现了归并排序的优点.典型的利用归并排序求逆

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

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

POJ 2299 Ultra-QuickSort (求逆序数:离散化+树状数组或者归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 55048   Accepted: 20256 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

POJ训练计划2299_Ultra-QuickSort(归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 39279   Accepted: 14163 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

HDU 4911 Inversion(归并排序求逆序数)

归并排序求逆序数,然后ans-k与0取一个最大值就可以了. 也可以用树状数组做,比赛的时候可能姿势不对,树状数组wa了.. Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 578    Accepted Submission(s): 249 Problem Description bobo has a seque

POJ2299 Ultra-QuickSort(归并排序求逆序数)

归并排序求逆序数 Time Limit:7000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u 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

归并排序求逆序数(排序算法)

归并排序:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并.--(摘自百度百科) 具体操作: 比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1:否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,

Ultra-QuickSort - poj 2299 (归并排序+统计逆序数)

利用归并排序统计逆序数,利用归并求逆序在对子序列s1和s2在归并时(s1,s2已经排好序),若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s2[j]都是逆序的. 1 #include <stdio.h> 2 #include <stdlib.h> 3 int N; 4 int num[500001]; 5 int tmp[500001]; 6 __int64 count; 7 void Merge(int l,int mi