由于本人在思索了很久后才把本题思路打通,所以为了帮助像我一样没有非常理解解法的人,我打算再将解法非常详细地叙述一遍,如果您无法理解解法,请跟着我再一步步将题目捋顺。
Step.1 解题意
题目要求其实很好理解,共给出 n n n 个点的位置,A,B两个人轮流取点,A要求最后剩下的两个点尽量近,B要求最后剩下的两个点尽量远。
Step.2 推一推
在这过程中,有一些东西可以被推知,这里做出详细的解释(由于解释太过于精细,dalao们请自行忽视):
-
一共有几个点?显然 n n n 个
-
最后剩下几个点?显然 2 2 2 个
-
综合 1 , 2 1,2 1,2,可知两人一共取走了 n − 2 n-2 n−2 个点
-
显然,两人取走的点是一样多的。也就是说,由于他们一共取走 n − 2 n-2 n−2 个点,因此 A A A 和 B B B 两人分别取走了 n − 2 2 \dfrac{n-2}{2} 2n−2 个点。而学过小学数学的人都知道:
n − 2 2 = n 2 − 2 2 = n 2 − 1 \dfrac{n-2}{2}=\dfrac{n}{2}-\dfrac{2}{2}=\dfrac{n}{2}-1 2n−2=2n−22=2n−1
所以,两人分别取走了 n 2 − 1 \dfrac{n}{2}-1 2n−1个点
5. A A A 会取哪些点? B B B 会取哪些点?这是理解本题的关键。首先有两个点能使A,B两人的收益同时最大(这不废话吗),但这两个点是固定的,即当数据给出时便已经确定。所以A为了使两点距离尽量近,会选择取走两点左右的点,更具体说,他会选择去掉端点位置的点。而B要使两点距离尽量远,会选择去掉两点中间位置的点。这里要注意的是,由于这两个点同时保证了A,B两人的利益最大化,所以两人都不会选择去掉这个点。
- 如何确定两点位置?这是构造代码的核心。这其实很好理解。尤其是我们已经得出了上面的结论。由于B只会取两点之间的点且B取了 n 2 − 1 \dfrac{n}{2}-1 2n−1 个点(前文已推知),因此最后剩下两点之间的距离为 ( n 2 − 1 ) + 1 = n 2 (\dfrac{n}{2}-1)+1=\dfrac{n}{2} (2n−1)+1=2n,即两点间距离等于点数加一,详情可以参照小学奥数:植树问题。(注意这里假设每个点间距离为 1 1 1)。设较近的点距离为 k k k,则较远的点距离为 k + n 2 k+\dfrac{n}{2} k+2n。
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>>1)
(n>>1) 代表
n
n
n 二进制右移一位,等价于
n
2
n\over 2
2n
写的这么认真,还不点赞吗?
求过QWQ