前言:
这题可以 s p l a y splay splay暴力模拟,可以双端队列模拟。
题目大意:
给一个序列。选择一个长度k,从左到右有顺序的进行 r e v e r s e reverse reverse或者不。问你是否能够将其变成有序.
题目思路:
方法一:双端队列
暴力模拟 O ( n 2 ) O(n^2) O(n2)。观察到这个过程是每次凑齐一个长度为 k k k的区间,然后考虑是否作整体反转.
谈到整体反转就可以使用双端队列。因为双端队列两边都可以出入队。所以正着读,反着读就相当于反转了。
做法1:自己实现六个函数(push_back,push_front,getback,getfront,pop_back,pop_front).根据反转标记来决定正反。比如说:push_back().如果有反转标记,就实际调用push_front,否则直接调用push_back.
做法2:额外维护一个镜像队列。同时操作且保证两者的操作是镜像的.然后将其中一个当作是当前队列。然后每次reverse的时候就转到另一个队列。
这里只放做法2.实现更简单
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
int a[maxn];
int tag = 1;
deque<int> q[2];
int b[maxn];
int main()
{
ios::sync_with_stdio(false);
int n; cin >> n;
for (int i = 1 ; i <= n ; i++) cin >> a[i] , b[a[i]] = i;
int id = 0 , k;
for (int i = 1 ; i <= n ; i++){
if (a[i] != i) {
id = i;
break;
}
}
k = b[id] - id + 1;
if (k == 1){
cout << "yes" << endl;
cout << k << endl;
return 0;
}
bool ok = true;
int now = id;
for (int i = id ; ; ){
while (i <= n && (int)q[tag].size() < k) {
q[tag].push_back(a[i]);
q[!tag].push_front(a[i]);
i++;
}
if ((int)q[tag].size() != k){
while (q[tag].size() && q[tag].front() == now) {
now++;
q[tag].pop_front();
q[!tag].pop_back();
}
if (q[tag].size()) ok = false;
break;
}
if (q[tag].back() == now){
q[tag].pop_back();
q[!tag].pop_front();
now++;
tag = !tag;
}
else if (q[tag].front() == now) {
q[tag].pop_front();
q[!tag].pop_back();
now++;
}
else {
ok = false;
break;
}
}
if (ok){
cout << "yes" << endl;
cout << k << endl;
return 0;
}
cout << "no" << endl;
return 0;
}