牛牛与交换排序 题解(双端队列模拟区间反转)

题目链接

题目大意

给你一个长度为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;
}

不摆烂了,写题
原文地址:https://www.cnblogs.com/hunxuewangzi/p/14453032.html