1. 程式人生 > 其它 >CF 1546C AquaMoon and Strange Sort

CF 1546C AquaMoon and Strange Sort

AquaMoon and Strange Sort---【思維】---★★☆☆☆

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;
}