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

浙公网安备 33010602011771号