HDU4911(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

大概意思:可以将相邻的两个数交换位置,最多可以交换k次,使得交换完后的逆序数最少。逆序数:1≤i<j≤n 并且满足ai>aj,就是一对逆序数。

思路:由于是相邻位置交换,交换一次最多减少一对逆序数,那么只要将初始的逆序数对数求出再减去k即可,若减完k后的结果小于0,那么输出0。
对于找逆序数,可以采用归并排序的方法。

原理:
如下图,因为归并前的两段数组分别都是有序的,假设有两段要归并的数组,t表示临时数组的下标,且t初始为i,比如在归并时第5位被放在了临时数组中的第2位,那么说明第5位之前有(5-2)=3个数比第5位大,即存在3对逆序数。继续归并,只要右端数组被归入了临时数组,那么cnt+=j-t,一直归并即可求出这两段数组中的逆序数对数。
在这里插入图片描述
下面是AC代码:

#include <bits/stdc++.h>
using namespace std;

int a[100005], temp[100005];
long long cnt = 0;

void Merge(int s, int m, int e)
{
    int i = s, j = m + 1, t = s;
    while (i <= m && j <= e)
    {
        if (a[i] <= a[j])//遇到相同的时候优先归并左侧的,因为左侧的原本就在前面
            temp[t] = a[i++];
        else
        {
            temp[t] = a[j];
            cnt += j - t;
            ++j;
        }
        ++t;
    }
    while (i <= m)
        temp[t++] = a[i++];
    while (s < j)//未归并的右侧不需要交换位置
    {
        a[s] = temp[s];
        s++;
    }
}

void Mergesort(int s, int e)
{
    if (s >= e)
        return;
    int m = (s + e) / 2;
    Mergesort(s, m);
    Mergesort(m + 1, e);
    Merge(s, m, e);
}

int main()
{
    int m;
    while (cin >> m)
    {
        for (int i = 1; i <= m; i++)
            cin >> a[i];
        Mergesort(1, m);
        cout << cnt << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值