题意
题目给出了一个长度为 n n n 的数组,要求我们构造一个数组的排序,这个排序要使这个数组每个数之间的差的绝对值最大值最小(包括第 1 1 1 个和第 n n n 个,即一个环)。
分析
这道题从哪里入手呢?首先观察样例。
输入:
5
2 1 1 3 2
输出:
1 2 3 2 1
那么通过观察发现,想要得到我们想要的结果,构造数组时要尽可能让大的数在中间,越小的数尽量往两边散开,使两边平衡。
比如,这个答案数组中间的数 3 3 3,是原数组中最大的那个数,而 3 3 3 左边和右边都是对称的,这样使得它们的每个数之间的差的绝对值最大值最小(包括第 1 1 1 个和第 n n n 个,即一个环)。
分析完毕,来讲讲如何实现:
-
我们先对数组进行从小到大的排序。
-
用双指针,一个记录头,一个记录尾。
-
将原数组的数交替存进答案数组的头和尾中。
-
最后记得特判一下 n n n 为奇数的情况,那么答案数组中间的那个数就是原数组最大的那个数。
这个思路能够直接在
5
×
1
0
6
5 \times 10^6
5×106 下通过,可以不需要优化输入输出速度。不过在赛场上容易卡常,建议使用 scanf();printf();
或 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
优化输出。
Code
// B4194.[海淀区小学组 2023] 生日
#include <cstdio>
#include <algorithm>
#define N 5000005
using namespace std;
int n, h, t, a[N], ans[N];
int main() {
scanf ("%d", &n);
for (int i = 1; i <= n; i++) scanf ("%d", &a[i]);
// 对数组进行排序
sort (a + 1, a + 1 + n);
t = n;
for (int i = 1; i <= n; i += 2) {
// 开始一头一尾重置新数组
ans[++h] = a[i];
ans[t--] = a[i + 1];
}
// 特判奇数个数的情况:新数组最中间的数是原数组最后一个数
if (n % 2 == 1) ans[h] = a[n];
for (int i = 1; i <= n; i++) printf ("%d ", ans[i]);
return 0;
}
完结撒花。