题目链接
题目大意
给你一个长度为n的全排列
你固定一个区间翻转长度k,你每次可以做任意次数的翻转
但是一旦某一次操作选择了数组的某个位置进行区间翻转操作,下一次做区间翻转的位置将会比上一次
更靠右。
要你判断是否能让数组变成升序,满足则输出k
题目思路
首先k一定是固定的,这应该稍微思考一下就懂
确定了k之后如何判读是否可以变成升序全排列是一个问题
暴力复杂度就是\(O(n^2)\)
而用splay可以优化,但是我不会splay
这个你仔细观察,只能翻转固定的长度
而且队首队尾的元素都要变化
就应该想到双端队列,翻转用一个标记即可,具体实现看代码
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
const int eps=1e-6;
int n,k;
int a[maxn];
int deq[maxn];
int pos[maxn];
bool pr=1;
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=1;i<=n;i++){
if(pos[i]>i){
k=pos[i]-i+1;
break;
}
}
if(k==0){ //直接一样就特判
printf("yes\n1\n");
return 0;
}
int head=n,tail=n-1;
for(int i=1;i<=k;i++){
deq[++tail]=a[i];
}
bool flag=1;
for(int i=1;i<=n;i++){
if(flag){
if(deq[head]!=i&&tail-head+1==k){
flag=0;
}
}else{
if(deq[tail]!=i&&tail-head+1==k){
flag=1;
}
}
if(flag){
if(deq[head]!=i){
pr=0;
break;
}
head++;
if(i+k<=n){
deq[++tail]=a[i+k];
}
}else{
if(deq[tail]!=i){
pr=0;
break;
}
tail--;
if(i+k<=n){
deq[--head]=a[i+k];
}
}
}
if(pr==0){
printf("no\n");
}else{
printf("yes\n%d\n",k);
}
return 0;
}