C. AquaMoon and Strange Sort
来源:https://codeforces.com/contest/1546/problem/C
标签:【思维】
题目简述
AquaMoon 有n个朋友,每个朋友穿的T-Shirt上都有一个数字,开始时所有的朋友有固定的位置,并且都面朝右方,现在AquaMoon想通过交换相邻的两个朋友,让数字呈非递减序列,注意,每次交换两人的朝向都会发生改变(左->右,右->左).要求排好序后所有人仍面朝右方。如果能够实现,输出YES,否则输出NO.
Input
输入由多个测试用例组成。第一行包含一个整数 t (1≤t≤50)ー测试用例数。
每个测试用例的第一行包含一个整数 n (1≤ n ≤10^5)ー Aquamoon 的好友数。
第二行包含 n 个整数 a1,a2,... ,an(1≤ ai ≤10^5)ー写在t恤上的数字。
保证所有测试用例的 n 之和不超过10^5。
Output
对于每个测试用例,如果存在一个可能的操作序列,输出“YES”(不带引号);否则,输出“NO”(不带引号)。
Sample Input
3
4
4 3 2 5
4
3 3 2 2
5
1 2 3 5 4
Sample Output
YES
YES
NO
More Info
第一个测试用例中可能的操作列表:
交换 a1和 a2。结果序列是3,4,2,5。方向是: 左,左,右,右。
交换 a2和 a3。结果序列是3,2,4,5。方向是: 左,左,右,右。
交换 a1和 a2。结果序列是2,3,4,5。方向是: 右,右,右,右。
题目思路
一个数要想变换后仍面朝右方,必然要经历偶数次变换。如果有一个数只能经历奇数次变换才能到达正确位置,则它必定会面向左。可以用对比初数列和排序后数列的下标之差求变换次数的奇偶性,但是遇到3,3,2,2这类含有重复数字的数列时就不好操作,因为两个相同的数(例如2,2)是可以通过互换改变两者的交换次数奇偶性的,而数列的递增递减性却没有改变;多个则更加麻烦。
我们可以换个思路,如果一个数经历了偶数次变换,则在变换前后的数列中它的下标的奇偶性是不会发生改变的,即原先奇数位的变换后仍在奇数位,偶数位的仍在偶数位。我们可以建立两个数组,一个用来存奇数位的数,另一个用来存偶数位的数;非递减排序后,依次从数组中去掉对应奇或偶位置的数,如果之间存储奇数位数字的数组有剩余或不够,必定有数的位置在排序后改变了奇偶性,偶数位亦然,输出NO。
代码(附注释)
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
const int N=100005;
int t,n;
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n;
int a[N],c1[N]={0},c2[N]={0};
for(int i=1;i<=n;i++){//分别用c1和c2存储奇、偶位置的数
cin>>a[i];
if(i%2!=0) c1[a[i]]++;
else c2[a[i]]++;
}
int flag=0;
sort(a+1,a+1+n);//排序
for(int i=1;i<=n;i++){//去除排序后奇、偶位置的数
if(i%2!=0&&c1[a[i]]) c1[a[i]]--;
else if(i%2==0&&c2[a[i]]) c2[a[i]]--;
else {
flag=1;break;
}
}
if(flag) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}