https://ac.nowcoder.com/acm/contest/9982/F
牛牛有一个数组,数组元素是1到n的排列,即数组的值在1~n范围内,且每个数字仅出现1次。
牛牛想要将该数组变为升序排列的,他可以进行如下的操作。
首先他要确定一个长度k,k的范围在1~n之间。
接下来他将会进行若干次操作。在每轮操作中他都可以选择一段长度为k的子数组,然后进行区间的翻转操作。
他可以做任意次数的操作,但是要求他每次选择的子数组区间满足li≤li+1,并且区间长度等于一开始选定的k,也就是说一旦某一次操作选择了数组的某个位置进行区间翻转操作,下一次做区间翻转的位置将会比上一次更靠右。
牛牛发现,并不总是存在一个k可以使得数组排序变为有序,请你告诉牛牛是否存在一个k能够在满足规则的情况下完成排序。
思路:可以发现找到一个和位置不对应的点就是k的答案。根据这个k去模拟,遇到不对的看一下翻转的对否就行。不对就gg。
至于翻转,reverse是O(n)的,这么干肯定不行。经常有翻转打lazy标记的。这题算个小trick.
deque是双端的,通过lazy标记可以知道当前应该从队头出还是队尾出,达到o(1)reverse的效果。
如果stl的deque常数大,可以手写。
附上出题人手写的deque板子。
struct deQue
{
int buffer[MAXN*2];
int head=MAXN,tail=MAXN-1;
bool rev;
bool empty()
{
return tail<head;
}
int size()
{
return tail-head+1;
}
int front()
{
return rev?buffer[tail]:buffer[head];
}
int back()
{
return rev?buffer[head]:buffer[tail];
}
void push_front(int x)
{
rev?buffer[++tail]=x:buffer[--head]=x;
}
void push_back(int x)
{
rev?buffer[--head]=x:buffer[++tail]=x;
}
void pop_back()
{
rev?head++:tail--;
}
void pop_front()
{
rev?tail--:head++;
}
void reverse()
{
rev^=1;
}
}q;
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<deque>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL a[maxn],pos[maxn];
deque<LL>que;
LL revtag=0;///表示正常的左边是队头
void pushbacknum(LL revtag,LL num){
if(revtag==0) que.push_back(num);
if(revtag==1) que.push_front(num);
}
LL getfront(LL revtag){///获得队首元素
if(revtag==0) return que.front();
if(revtag==1) return que.back();
return 0;
}
void popfront(LL revtag){///弹出队首元素
if(revtag==0) que.pop_front();
if(revtag==1) que.pop_back();
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n;cin>>n;
for(LL i=1;i<=n;i++){
cin>>a[i];
pos[a[i]]=i;
}
bool flag=1;LL k=0;
for(LL i=1;i<=n;i++){
if(a[i]!=i){
k=(pos[i]-i+1);
flag=0;
break;
}
}
if(flag==1){
cout<<"yes"<<"\n"<<1<<"\n";
return 0;
}
flag=1;
for(LL i=1;i<=k;i++){
pushbacknum(revtag,a[i]);
}
for(LL i=1;i<=n;i++){
/// cout<<"i="<<i<<" "<<"队首元素为:"<<getfront(revtag)<<'\n';
if(getfront(revtag)!=i&&que.size()==k) revtag^=1;///当前不对应,反转一下
if(getfront(revtag)!=i){
///cout<<"i="<<i<<" "<<"队首元素为:"<<getfront(revtag)<<'\n';
flag=0;
break;
}
popfront(revtag);
if(i+k<=n) {
pushbacknum(revtag,a[i+k]);
/// cout<<"加入:"<<a[i+k]<<'\n';
}
}
if(flag==1){
cout<<"yes"<<"\n";
cout<<k<<"\n";
}
else if(flag==0) cout<<"no"<<"\n";
return 0;
}