ABC302G Sort from 1 to 4 [關鍵性質題]

chenwenmo發表於2024-10-11

Description

給定一個長度為 \(N\) 的序列,其中每個元素都是介於 \(1\)\(4\) 之間的整數。

可以進行以下操作任意次(可能為零次):

  • 選擇一對整數 \((i, j)\),其中 \(1≤i<j≤N\),並交換 \(A_i\)\(A_j\)

輸出使序列 \(A\) 變為非遞減序列所需的最小操作次數。

Solution

對於這種交換數字,最小運算元是序列相等,或者什麼單調性的題,可以優先想到逆序對和建圖。

設原序列為 \(A=(A_1, A_2, ..., A_N)\),排序後為 \(B=(B_1, B_2, ..., B_N)\)

根據觀察,若 \(A_i\ne B_i\),則我們用它們代表的數字建邊 \(A_i\to B_i\)

由於每個點的出度和入度都相等,所以最終會形成若干個環,且根據 \(A_i\in [1,4]\) 這重要性質,可知環長不超過 \(4\)

考慮一個長度為 \(i\) 的環,要把它變為合法,需要 \(i-1\) 步,因此我們優先把長度為 \(2\) 的環交換,接著是 \(3\),最後是 \(4\),直接暴力列舉計算貢獻即可。

Code

const int N = 2e5 + 5;

int n, a[N], b[N], e[5][5];

void Solve(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + 1 + n);
    for(int i = 1; i <= n; i++){
        if(a[i] != b[i]) e[a[i]][b[i]]++;
    }

    ll ans = 0;

    for(int i = 1; i <= 4; i++){
        for(int j = 1; j <= 4; j++){
            if(e[i][j] && e[j][i]){
                ll mn = min(e[i][j], e[j][i]);
                ans += mn;
                e[i][j] -= mn;
                e[j][i] -= mn;
            }
        }
    }

    for(int i = 1; i <= 4; i++){
        for(int j = 1; j <= 4; j++){
            for(int k = 1; k <= 4; k++){
                if(i == j || j == k || k == i) continue;
                if(e[i][j] && e[j][k] && e[k][i]){
                    ll mn = min({e[i][j], e[j][k], e[k][i]});
                    ans += mn * 2;
                    e[i][j] -= mn;
                    e[j][k] -= mn;
                    e[k][i] -= mn;
                }
            }
        }
    }

    ll tmp = 0;
    for(int i = 1; i <= 4; i++){
        for(int j = 1; j <= 4; j++){
            tmp += e[i][j];
        }
    }
    tmp /= 4;
    tmp *= 3;
    ans += tmp;

    cout << ans << endl;
}

相關文章