简单分析后可知
- 第一次操作必然使最小的、不在其位的数让它归位
- 那么长度就已经固定了
- 那么接下来要做的就是模拟,看能否完成排序即可
可以用deque双端队列模拟,也可以用平衡树
#include <bits/stdc++.h> #define sc(x) scanf("%d", &(x)) #define pr(x) printf("%lld\n", (x)) #define rep(i, l, r) for (int i = (l); i <= (r); ++i) using namespace std; typedef long long ll; const int N = 1e5 + 7; const int mod = 1e9 + 7; int n, a[N]; deque<int> q; int main() { sc(n); rep(i, 1, n) sc(a[i]); int x = 0; //第一个不在正确位置上的数 // aka 不在正确位置上的 最小的数 rep(i, 1, n) if (a[i] != i) { x = i; break; } if (!x) return puts("yes\n1"), 0; //当前已经有序 int now, len; rep(i, x + 1, n) if (a[i] == x) { now = i; // 这个最小的错位数 现在在now这个位置 len = i - x + 1; // 需要翻转的线段长度 break; } rep(i, x, now - 1) q.emplace_front(a[i]); bool tag = 0; for (int i = x; i + len - 1 <= n; i++) { if (!tag) q.emplace_front(a[i + len - 1]); else q.emplace_back(a[i + len - 1]); if (tag) { if (q.front() != i) tag = 0; } else { if (q.back() != i) tag = 1; } if (tag) { if (q.front() != i) return puts("no"), 0; q.pop_front(); } else { if (q.back() != i) return puts("no"), 0; q.pop_back(); } } for (int i = n - len + 2; i <= n; i++) { if (tag) { if (q.front() != i) return puts("no"), 0; q.pop_front(); } else { if (q.back() != i) return puts("no"), 0; q.pop_back(); } } printf("yes\n%d", len); return 0; }