问题描述
给定 n n n个整数 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an。是否有办法将它们排列成一个环使得每个元素严格大于邻近的两个元素或者严格小于邻近的两个元素?
换句话说,检查是否有一个整数序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an的重排 b 1 , b 2 , … , b n b_1,b_2,\dots,b_n b1,b2,…,bn使得对任意的 i i i以下两个条件中满足任何一个:
b i − 1 < b i > b i + 1 b_{i-1}<b_i>b_{i+1} bi−1<bi>bi+1
b i − 1 > b i < b i + 1 b_{i-1}>b_i<b_{i+1} bi−1>bi<bi+1
为了使得这些式子在 i = 1 i=1 i=1和 i = n i=n i=n时仍然有意义, b 0 = b n b_0=b_n b0=bn且 b n + 1 = b 1 b_{n+1}=b_1 bn+1=b1。
输入格式
输入的第一行为一个整数 t ( 1 ≤ t ≤ 3 ⋅ 1 0 4 ) t (1\le t \le 3 \cdot 10 ^ 4) t(1≤t≤3⋅104)表示测试数据的组数。测试数据的描述如下。
第一行为一个整数 n ( 3 ≤ n ≤ 1 0 5 ) n(3 \le n \le 10^5) n(3≤n≤105)表示整数的个数。
第二行为 n n n个整数 a 1 , a 2 , … , a n ( 0 ≤ a i ≤ 1 0 9 ) a_1,a_2,\dots,a_n (0 \le a_i \le 10^9) a1,a2,…,an(0≤ai≤109)。
每个测试数据的 n n n之和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
输出格式
对所有测试数据,如果无法将它们排列成对应的条件,输出NO
。
否则输出YES
,在第二行输出
n
n
n个整数
b
1
,
b
2
,
…
,
b
n
b_1,b_2,\dots,b_n
b1,b2,…,bn,表示符合题意的
a
1
,
a
2
,
⋯
,
a
n
a_1,a_2,\cdots,a_n
a1,a2,⋯,an的重排。如果有多种答案,请输出任何一种。
可以输出任何大小写的YES
和NO
。
输入输出样例
输入 | 输出 |
---|---|
4 3 1 1 2 4 1 9 8 4 4 2 0 2 2 6 1 1 1 11 111 1111 | NO YES 1 8 4 9 NO YES 1 11 1 111 1 1111 |
样例解释
对第一个测试点和第三个测试点无解。
第二个测试点, [ 1 , 8 , 4 , 9 ] [1,8,4,9] [1,8,4,9]为该问题的解。在这个排列中, 1 1 1和 4 4 4比它们的邻近的数字小, 8 8 8和 9 9 9比它们的邻近数字大。
第四个测试点, [ 1 , 11 , 1 , 111 , 1 , 1111 ] [1,11,1,111,1,1111] [1,11,1,111,1,1111]为该问题的解。在这个排列中,三个 1 1 1比它们邻近的数字小,其他元素比它们的邻近数字大。
题解
思路:首先给数组排序,记排序后的新数组为 c i c_i ci
则有 c 1 < c 2 < ⋯ < c n c_1<c_2< \dots <c_n c1<c2<⋯<cn。
排好序之后,问题就变得很简单了。
问题要求严格大于或者严格小于,就要尽量减少元素重复。
所以应该间隔安插元素。
贪心的过程中,如果 n n n为奇数,无解。取 n = 3 n=3 n=3的例子读者可以自己列出来。
一般地,假定 < < <和 > > >交替,那么 b 1 < b 2 b_1<b_2 b1<b2, b 3 < b 4 b_3<b_4 b3<b4, b 2 > b 3 b_2>b_3 b2>b3, b 4 > b 5 b_4>b_5 b4>b5,……
b 2 n > b 2 n + 1 b_{2n}>b_{2n+1} b2n>b2n+1, b 2 n + 1 < b 1 b_{2n+1}<b_1 b2n+1<b1
然而我们的构造方法, b 1 < b 2 n + 1 b_1<b_{2n+1} b1<b2n+1,矛盾。
偶数的情况就一定有结果。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int a[100005],b[100005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
a[0]=a[n];
a[n+1]=a[1];
int flag=1;
b[0]=-1; //注意
if(n%2==0)
{
for(int i=1;i<=n;i++)
{
if(i%2) b[i]=a[i/2+1];
else b[i]=a[i/2+(n+1)/2];
if(b[i]==b[i-1])
{
flag=0;
break;
}
}
if(b[n]==b[1]) flag=0;
if(flag)
{
printf("YES\n");
for(int i=1;i<=n;i++) printf("%d ",b[i]);
printf("\n");
}
else printf("NO\n");
}
else printf("NO\n");
}
return 0;
}