牛客周赛 Round 55 C题
小红的数组重排
题目背景
牛客周赛 Round 55
题目描述
样例 #1
样例输入 #1
4
7 2 5 1
样例输出 #1
YES
1 5 2 7
样例 #1
样例输入 #1
6
1 1 4 5 1 4
样例输出 #1
NO
做题思路
a 1 ∗ a 2 < a 2 ∗ a 3 < . . . < a n − 1 ∗ a n a_1*a_2 \lt a_2 * a_3 \lt ... \lt a_{n-1} * a_n a1∗a2<a2∗a3<...<an−1∗an
拆解不等式变为
a
1
∗
a
2
<
a
2
∗
a
3
a_1*a_2 \lt a_2 * a_3
a1∗a2<a2∗a3
a
2
∗
a
3
<
a
3
∗
a
4
a_2*a_3 \lt a_3 * a_4
a2∗a3<a3∗a4
a
3
∗
a
4
<
a
4
∗
a
5
a_3*a_4 \lt a_4 * a_5
a3∗a4<a4∗a5
…
a
n
−
2
∗
a
n
−
1
<
a
n
−
1
∗
a
n
a_{n-2}*a_{n-1} \lt a_{n-1} * a_n
an−2∗an−1<an−1∗an
将上述不等式左右两边相等的消去可得
a
1
<
a
3
a_1 \lt a_3
a1<a3
a
2
<
a
4
a_2 \lt a_4
a2<a4
a
3
<
a
5
a_3 \lt a_5
a3<a5
…
a
n
−
3
<
a
n
−
1
a_{n-3} \lt a_{n-1}
an−3<an−1
a
n
−
2
<
a
n
a_{n-2} \lt a_n
an−2<an
再把不等式进行拼接发现
a
1
<
a
3
<
a
5
.
.
.
<
a
n
,
(
n
为奇数
)
a_1 \lt a_3 \lt a_5 ... \lt a_n , (n为奇数)
a1<a3<a5...<an,(n为奇数)
a
2
<
a
4
<
a
6
.
.
.
<
a
n
−
1
,
(
n
为奇数
)
a_2 \lt a_4 \lt a_6 ... \lt a_{n-1} , (n为奇数)
a2<a4<a6...<an−1,(n为奇数)
变成两个不等式链。
如果出现两个相同的数字,可以分别放入两个不等式链中使其成立,如果出现三个数字相等,由鸽巢定理可得至少有两个相等的数字会出现在同一个不等式链中,因为不等式链是严苛的,所以必定不成立。
所以判断是否可行的第一点就是判断是否出现三个及以上的数字相同。
但要注意一点是,对于0的个数的判断。
如果0出现了两次,那么必定会导致原本的不等式链 a x ∗ a x + 1 < a x + 1 ∗ a x + 2 a_x * a_{x+1} \lt a_{x+1} * a_{x+2} ax∗ax+1<ax+1∗ax+2不成立,因为只要0出现了两次,那么无论怎么排序,0必定会出现在不等式的两端。
最后如果能够成立,仅需将原数组排序即可,因为相同的两个数字会分到奇偶两个下标,进入不同的等式链中。
代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <tuple>
#include <cstring>
#include <cmath>
#include <cstdio>
#define int long long
using namespace std;
const int N = 5e5+10;
const int INF = 0x3f3f3f3f3f3f3f3f;
int bt[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
int n,m;
int a[N];
void init(){
}
void solve(){
init();
cin >> n ;
map<int,int>mp;
for(int i=1;i<=n;i++) {
cin >> a[i];
mp[a[i]]++;
if(mp[a[i]] > 2) { cout << "NO";return ; }
}
if(mp[0]==2){
cout << "NO";return ;
}
cout << "YES\n";
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)cout << a[i] << ' ';
}
signed main(){
int _=1;//cin >> _;
while(_--)solve();
return 0;
}