AtCoder题解—— AtCoder Beginner Contest 181 —— E - Transformable Teacher

题目相关

题目链接

AtCoder Beginner Contest 181 E 题,https://atcoder.jp/contests/abc181/tasks/abc181_e

Problem Statement

There are N children in a kindergarten. The height of the i-th child is Hi. Here, N is an odd number.

You, the teacher, and these children - N+1 people in total - will make \frac{N+1}{2} pairs.

Your objective is to minimize the sum of the differences in height over those pairs. That is, you want to minimize \sum_{i=1}^{\frac{n+1}{2}}\left | x_i-y_i \right | , where (xi,yi) is the pair of heights of people in the i-th pair.

You have M forms that you can transform into. Your height in the i-th form is Wi.

Find the minimum possible sum of the differences in height over all pairs, achieved by optimally choosing your form and making pairs.

Input

Input is given from Standard Input in the following format:

N M
H1 ... HN
W1 ... WM

Output

Print the minimum possible sum of the differences in height over all pairs, achieved by optimally choosing your form and making pairs.

Samples1

Sample Input 1

5 3
1 2 3 4 7
1 3 8

Sample Output 1

3

Explaination

The minimum is minimized by choosing the form with the height 8 and making pairs with heights (1,2), (3,4), and (7,8).

Samples2

Sample Input 2

7 7
31 60 84 23 16 13 32
96 80 73 76 87 57 29

Sample Output 2

34

Samples3

Sample Input 3

15 10
554 525 541 814 661 279 668 360 382 175 833 783 688 793 736
496 732 455 306 189 207 976 73 567 759

Sample Output 2

239

Constraints

  • All values in input are integers.
  • 1≤N,M≤2×10^5
  • N is an odd number.
  • 1≤Hi≤10^9
  • 1≤Wi≤10^9

题解报告

题目翻译

幼儿园里有 N 个(N 是一个奇数)小朋友,队列 H 的第 i 个个数据表示小朋友身高为 Hi。你,一个老师,和这 N 个小朋友可以构成 \frac{N+1}{2} 个数对。我们的目标是这写数对的身高绝对值总和为最小。

你的身高有 M 种可能,队列 W 的第 i 个个数据表示你的身高为 Wi。

题目分析

本题的要求从 W 队列中选出一个合适的数据,插入到 H 队列中,使得 H 队列中两两配对,身高差总和最小。

我们可以将问题先简化,变成一个 N 个身高的队列,N 为偶数,两两配对,身高差总和最小。我们知道这个问题的最小值必然是将队列排序后,这样两两组合身高差才能最小。我们可以用数学归纳法进行证明。证明过程就不写了。大家可以通过分治的思路来思考一下,就可以得出这个结论。

比如身高为:{1 4 5 3 9 6},排序后变成 {1 3 4 5 6 9},那么对应的最小总和为:(3-1)+(5-4)+(9-6)=2+1+3=6。

暴力枚举

这样,我们发现只需要遍历将 W,将 W 的每个值插入到队列 H 中,然后计算一下结果,选择其中最小的就可以解决问题,这样的暴力枚举算法的时间复杂度为 O(M*N)。但是问题来了题目提供的数据为 2*10^5 个,最大情况是,我们需要计算 2*10^5 次,每次计算 2*10^5 个数据。这样计算我们比如是 TLE。下面我们来看看如何化简操作。

优化问题

我们前面讨论过,对数据进行预处理的方法只有前缀和。本题需要将数据两两配对,由于 N 是奇数,因此我们可以考虑进行两次预处理:

1、从第一个数据开始到最后一个数据,每两个数据的差进行一次前缀和。将数据保存在数组 qsum 中。

2、从最后一个数据开始到第一个数据,每两个数据的差进行一次前缀和。将数据保存在数组 hsum 中。

下面我们在讨论一下插入位置。我们将一个 Wx 插入到 H 中,这样只有两个可能:可能一,插入位置为奇数;可能二,插入位置为偶数。用简单的数据来说明一下,假如我们在 {a b c d e} 中插入数据 x,其中原来队列是排序好的。

第一种情况,插入在奇数位置。假设 c<x<d,那么对应的数列变成 {a b c x d e},对应的结果为:(b-a)+(x-c)+(d-e)\equiv \left | b-a \right |+\left | c-x \right |+\left | d-e \right |

第二种情况,插入在偶数位置。假设 b<x<c,那么对应的数列变成 {a b x c d e},对应的结果为:(b-a)+(c-x)+(d-e)\equiv \left | b-a \right |+\left | x-c \right |+\left | d-e \right |

我们可以发现,这两个结果是一样的。什么意思?插入到偶数还是奇数,不影响计算结果。

这样我们就可以使用二分查找来解决问题,这样我们将查找的时间复杂度从 O(N*M) 下降为 O(M*logN)。

对应的最优解为:

min(ans, qsum[pos-1]+hsum[pos+1]+abs(h[pos]-w[i]))

AC 参考代码

//https://atcoder.jp/contests/abc181/tasks/abc181_e
//E - Transformable Teacher
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int MAXN=2e5+4;
LL h[MAXN];
LL qsum[MAXN];
LL hsum[MAXN];

const int MAXM=2e5+4;
LL w[MAXM];

int main() {
    //快读
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n,m;
    cin>>n>>m;

    //读取小朋友身高
    for (int i=1; i<=n; i++) {
        cin>>h[i];
    }
    //数据处理
    sort(h+1, h+n+1);
    //计算前缀和
    for (int i=2; i<=n; i+=2) {
        qsum[i] = qsum[i-2]+abs(h[i]-h[i-1]);
    }
    //计算后缀差
    for (int i=n-1; i>=1; i-=2) {
        hsum[i] = hsum[i+2]+abs(h[i+1]-h[i]);
    }

    //读取老师身高
    for (int i=1; i<=m; i++) {
        cin>>w[i];
    }

    //将老师的身高 w[i] 插入到 h 中二分查找
    LL ans=LONG_LONG_MAX;
    for (int i=1; i<=m; i++) {
        // pos为插入位置
        int pos = lower_bound(h+1, h+1+n, w[i]) - h;
        if (0==pos%2) {
            pos--;
        }
        ans = min(ans, qsum[pos-1]+hsum[pos+1]+abs(h[pos]-w[i]));
    }

    cout<<ans<<"\n";

    return 0;
}

89 ms 使用了快读,167 ms 没有使用快读。

时间复杂度

O(M*logN)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值