Codeforces 1685A

问题描述

给定 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} bi1<bi>bi+1

b i − 1 > b i < b i + 1 b_{i-1}>b_i<b_{i+1} bi1>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(1t3104)表示测试数据的组数。测试数据的描述如下。

第一行为一个整数 n ( 3 ≤ n ≤ 1 0 5 ) n(3 \le n \le 10^5) n(3n105)表示整数的个数。

第二行为 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(0ai109)

每个测试数据的 n n n之和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2105

输出格式

对所有测试数据,如果无法将它们排列成对应的条件,输出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的重排。如果有多种答案,请输出任何一种。

可以输出任何大小写的YESNO

输入输出样例

输入输出
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值