HDU-P4911:Inversion[归并排序]

HDU-P4911:Inversion[归并排序]

题目

题目链接

Problem Description

bobo has a sequence a1,a2,…,an. 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 ai>aj.

Input

The input consists of several tests. For each tests:

The first line contains 2 integers n,k (1≤n≤105,0≤k≤109). The second line contains n integers a1,a2,…,an (0≤ai≤109).

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

题目大意

输入第一行给出需处理数据的个数和处理次数的限制,第二行给出数据。
输出是数据求出经过处理后,这组数据中最少的逆序列 的个数。
根据题意,我们可以对相邻的一对数字进行交换,显然每一次交换我们都可以使逆序列的个数减少1,所以我们要求解的问题与接下来的问题等价:寻找给出数据中逆序列的个数。
首先容易想到的暴力解法显然会超时,我们需要一个时间复杂度更优的解法,若对一个局部有序的数据进行比较即可大大缩短求解所需的时间,归并排序就可以实现类似的功能,只需要在归并排序中加入一行计数的代码即可。
对代码的合理性解释如下:Merge实现了计算两个有序组间可以组成逆序列的对数,由于递归程序是自小问题向大问题运行的,故在最大的分组计算有序组间逆序列个数之前,各个有序的组内逆序列的个数都已经计算出,故本组内顺序的调整也并不会影响计算结果的正确性。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 5e5;
int a[N], tmp[N];
long long cnt;

void Merge(int s, int m ,int e) {
    int p = 0, i = s, j = m+1;
    while(i <= m && j <= e) {
        if(a[i] <= a[j])
            tmp[p++] = a[i++];
        else {
            cnt += j-s+p; //计数代码,实现了计算分成的两组之间的逆序列的计算
            tmp[p++] = a[j++];
        }
    }
    while(i<=m) tmp[p++] = a[i++];
    while(j<=e) tmp[p++] = a[j++];
    for(int i = s; i <= e; ++i) {
        a[i] = tmp[i-s];
    }
}
void Mergesort(int s, int e) {
    if(s < e) {
        int mid = (s+e)/2;
        Mergesort(s, mid);
        Mergesort(mid+1, e);
        Merge(s, mid, e);
    }
}
int main(void)
{
    int n, k;
    while(~scanf("%d%d", &n, &k)) {
        for(int i = 0; i < n; ++i) {
            scanf("%d", &a[i]);
        }
        cnt = 0;
        Mergesort(0, n-1);
        printf("%lld\n", cnt>k?cnt-k:0); //给出的k值可能会大于实际需要的次数
    }
    return 0;
}

题目的代码难度不大,主要难度存在于对题目的理解和解法的思考。代码思路是借鉴了很多大佬的思路,如对代码有任何建议或意见,欢迎探讨。


  1. 对于一组数字a[n],如果存在i<j并且a[i]>a[j],则称其为一组逆序列。 ↩︎

posted @   JACK121385  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示