CF1907F 题解

题意

对于数组 \(a\),可以将其整体反转或者是向右移一位,即对于 \(\forall_{1\le i<n} a[i]\rightarrow a[i+1], a[n] \rightarrow a[1]\)。问是否可通过最少的次数将数组升序排序。

题解

发现向右移操作是建立在环上的,且反转操作和右移操作均不影响环上元素的相对顺序,判断如果环上元素是非单调的则无解,否则原数组可以表示为两个单调不降或不升序列拼在一起,分类之:

若原数组升序,序列的断点在 \(p\),则有:\(rs=\min(n-p+1,p+1)\)

前者后者分别对应直接转过去,先翻转一次在转成下降序列再反转回来。

原数组降序可同理推得。

易于证明,这样的做法是 \(O(n)\) 的,复杂度在于判断合法和找到断点。

#include<algorithm>
#include<iostream>
using std::min;
int t, n, cu, cd, pu, pd, a[100005];
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);std::cout.tie(0);
    std::cin >> t;
    while(t--){
        std::cin >> n; cu = cd = pu = pd = 0;
        for(int i = 1; i <= n; i++) std::cin >> a[i];
        for(int i = 1; i < n; i++)
            if(a[i] > a[i + 1]) ++cu, pu = i + 1;
        for(int i = 1; i < n; i++)
            if(a[i] < a[i + 1]) ++cd, pd = i + 1;
        if(cu == 0) {std::cout << "0\n"; continue;}
        if(cd == 0) {std::cout << "1\n"; continue;}
        if(cu > 1 && cd > 1) {std::cout << "-1\n"; continue;}
        int rs = 0x7fffffff;
        if(cu == 1 && a[1] >= a[n]) rs = min(rs, min(n - pu + 1, pu + 1));
        if(cd == 1 && a[1] <= a[n]) rs = min(rs, min(n - pd + 2, pd));
        std::cout << (rs == 0x7fffffff ? -1 : rs) << '\n';
    }
}
posted @ 2023-12-11 07:37  xlpg0713  阅读(23)  评论(0)    收藏  举报