题目相关
题目链接
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 pairs.
Your objective is to minimize the sum of the differences in height over those pairs. That is, you want to minimize , 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 个小朋友可以构成 个数对。我们的目标是这写数对的身高绝对值总和为最小。
你的身高有 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<x<c,那么对应的数列变成 {a b x c d e},对应的结果为:。
我们可以发现,这两个结果是一样的。什么意思?插入到偶数还是奇数,不影响计算结果。
这样我们就可以使用二分查找来解决问题,这样我们将查找的时间复杂度从 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)