CF594A Warrior and Archer 题解

由于本人在思索了很久后才把本题思路打通,所以为了帮助像我一样没有非常理解解法的人,我打算再将解法非常详细地叙述一遍,如果您无法理解解法,请跟着我再一步步将题目捋顺。

Step.1 解题意

题目要求其实很好理解,共给出 \(n\) 个点的位置,A,B两个人轮流取点,A要求最后剩下的两个点尽量近,B要求最后剩下的两个点尽量远。

Step.2 推一推

在这过程中,有一些东西可以被推知,这里做出详细的解释(由于解释太过于精细,dalao们请自行忽视):

  1. 一共有几个点?显然 \(n\)

  2. 最后剩下几个点?显然 \(2\)

  3. 综合 \(1,2\),可知两人一共取走了 \(n-2\) 个点

  4. 显然,两人取走的点是一样多的。也就是说,由于他们一共取走 \(n-2\) 个点,因此 \(A\)\(B\) 两人分别取走了 \(\dfrac{n-2}{2}\) 个点。而学过小学数学的人都知道:

\[\dfrac{n-2}{2}=\dfrac{n}{2}-\dfrac{2}{2}=\dfrac{n}{2}-1 \]

所以,两人分别取走了 \(\dfrac{n}{2}-1\)个点

5.\(A\) 会取哪些点?\(B\) 会取哪些点?这是理解本题的关键。首先有两个点能使A,B两人的收益同时最大(这不废话吗),但这两个点是固定的,即当数据给出时便已经确定。所以A为了使两点距离尽量近,会选择取走两点左右的点,更具体说,他会选择去掉端点位置的点。而B要使两点距离尽量远,会选择去掉两点中间位置的点。这里要注意的是,由于这两个点同时保证了A,B两人的利益最大化,所以两人都不会选择去掉这个点。

  1. 如何确定两点位置?这是构造代码的核心。这其实很好理解。尤其是我们已经得出了上面的结论。由于B只会取两点之间的点且B取了 \(\dfrac{n}{2}-1\) 个点(前文已推知),因此最后剩下两点之间的距离为 \((\dfrac{n}{2}-1)+1=\dfrac{n}{2}\),即两点间距离等于点数加一,详情可以参照小学奥数:植树问题。(注意这里假设每个点间距离为 \(1\))。设较近的点距离为 \(k\),则较远的点距离为 \(k+\dfrac{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

posted @ 2023-04-02 09:51  ZyIOLO  阅读(16)  评论(0编辑  收藏  举报