由于本人在思索了很久后才把本题思路打通,所以为了帮助像我一样没有非常理解解法的人,我打算再将解法非常详细地叙述一遍,如果您无法理解解法,请跟着我再一步步将题目捋顺。
Step.1 解题意
题目要求其实很好理解,共给出 \(n\) 个点的位置,A,B两个人轮流取点,A要求最后剩下的两个点尽量近,B要求最后剩下的两个点尽量远。
Step.2 推一推
在这过程中,有一些东西可以被推知,这里做出详细的解释(由于解释太过于精细,dalao们请自行忽视):
-
一共有几个点?显然 \(n\) 个
-
最后剩下几个点?显然 \(2\) 个
-
综合 \(1,2\),可知两人一共取走了 \(n-2\) 个点
-
显然,两人取走的点是一样多的。也就是说,由于他们一共取走 \(n-2\) 个点,因此 \(A\) 和 \(B\) 两人分别取走了 \(\frac{n-2}{2}\) 个点。而学过小学数学的人都知道:
所以,两人分别取走了 \(\frac{n}{2}-1\)个点
5.\(A\) 会取哪些点?\(B\) 会取哪些点?这是理解本题的关键。首先有两个点能使A,B两人的收益同时最大(这不废话吗),但这两个点是固定的,即当数据给出时便已经确定。所以A为了使两点距离尽量近,会选择取走两点左右的点,更具体说,他会选择去掉端点位置的点。而B要使两点距离尽量远,会选择去掉两点中间位置的点。这里要注意的是,由于这两个点同时保证了A,B两人的利益最大化,所以两人都不会选择去掉这个点。
- 如何确定两点位置?这是构造代码的核心。这其实很好理解。尤其是我们已经得出了上面的结论。由于B只会取两点之间的点且B取了 \(\frac{n}{2}-1\) 个点(前文已推知),因此最后剩下两点之间的距离为 \((\frac{n}{2}-1)+1=\frac{n}{2}\),即两点间距离等于点数加一,详情可以参照小学奥数:植树问题。(注意这里假设每个点间距离为 \(1\))。设较近的点距离为 \(k\),则较远的点距离为 \(k+\frac{n}{2}\)。
Step.3 码一码(构造代码)
我们知道了剩余两个点的位置关系,就可以通过枚举第一个点的位置,得到第二个点的位置,得到两点间的距离。那如何确定当前枚举的情况是好的呢?由于A先取,具有先手优势,于是我们应当取两个点之间的距离最小值。
需要注意的一点是,在枚举之前,由于输入的序列没有单调性,于是我们应先将其排序。
代码如下:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 2e5 + 5;
int n;
int a[N];
int ans = (1 << 30);
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= (n >> 1); i ++) {
ans = min(a[i + (n >> 1)] - a[i], ans);
}
cout << ans << endl;
return 0;
}
这里对位运算作出解释:\((n>>1)\) 代表 \(n\) 二进制右移一位,等价于 \(n\over 2\)
写的这么认真,还不点赞吗?
求过QWQ