牛牛与交换排序

在这里插入图片描述
输入:
样例1
5
1 2 3 4 5

样例2
5
1 2 3 4 5

样例3
5
5 4 3 2 1

输出:
样例1
yes
3

样例2
yes
1

样例3
yes
5
思路: 模拟 / 双端队列
首先明确,k是唯一的(所以题目有误导的成分),因为翻转操作的区间是逐步向右移的,也就是区间左边的数一旦确定下来,便没有后悔的机会了,对于区间最左边的数,只有一次机会翻转到自己的位置。
这题暴力不会tle,模拟一下翻转操作是可取的
优化一下,将翻转操作转化为对双端队列的插头和插尾操作。
因为翻转操作为偶数时,顺序是不变的,所以翻转操作转奇数时,下一个元素插头,然后删尾,偶数时相反。注意如果不用翻转操作时(即元素在它自己该在位置上,插入和删除的元素应该和翻转的操作相反,原来删头,现在应该删尾@-@
比如对于2 1 3 4,一开始队列里是 2 1,并且队列是从左向右读,第一翻转后为1 2 3 4 ,此时队列应该从右向左读,3插头,删去尾部的1,变为3 2,以此类推。
值得留意的是,当处理到最后n-k+1个数字时,不会再入队了,应该后面没数字入了,循环应该停止,接着去检查队列的数字是否升序或者降序。
比如对于 1 2 3 5 6 4,循环的最后一次检查是5 6 4,判断5不在自己的位置上,然后翻转变成4 6 5,判断4在自己的位置上就结束了,还要再进队列里,判6 5的顺序是否合法 ,
ps:手工开队列模拟,比stl快,直接给个flag,每次翻转改flag,将队列尾部转为头部,代码清晰许多,为了给自己增加难度,我还是选择stl了>-<

// 双端队列
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

deque<int > q;
bool boo=1;
int arr[100000];
int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    int flag=1,pos=-1; //1从左边翻转 0从右边,pos 记录第一个开始翻转的位置
    int n;
    cin>>n;
    for(int i=1;i<=n ;i++)  cin>>arr[i];
    
    
    //先求k,k是唯一的
    int k=0;
    for(int i=1; i<=n ;i++)
    {
    
    
        if( arr[i]!=i )
        {
    
    
          pos=i; //记录开始翻转的位置
          for(int j=i+1; j<=n;j++)
          {
    
    
              if(arr[j]==i)
              {
    
    
                  k=j-i+1;
                  break;
              }
          }
            break;
        }
    }
    if( k==0 )  {
    
    cout<<"yes\n1";return 0;}//特判,如果k==0,直接输出
   
    //第一批需要翻转的区间入队
    for(int i=pos;i<=pos+k-1;i++)
        q.push_back(arr[i]);

    //翻转处理,从第一个需要翻转的位置,最后位置截止到n-k+1
    for(int i=pos ;i+k-1<=n ;i++)
        if(flag)
        {
    
    
            if( q.front()!=i )
            {
    
    
                flag^=1;
            if(q.back()!=i) {
    
    boo=0;break;}
            q.pop_back();
            if(i+k<=n)
            q.push_front(arr[i+k]);
            }
            else
            {
    
    
                 q.pop_front();
                 if(i+k<=n)
             q.push_back(arr[i+k]);
            }
        }
        else
        {
    
    
            if(q.back()!=i )
            {
    
    
                flag^=1;
             if(q.front()!=i) {
    
    boo=0;break;}
               q.pop_front();
                 if(i+k<=n)
             q.push_back(arr[i+k]);

            }
            else
            {
    
    
                int x=q.back(),y=i+k;
             q.pop_back();
            if(i+k<=n)
            q.push_front(arr[i+k]);
            }
        }
    //最后处理队列里的k个数字,只要看是否升序或者降序即可
    if(flag==1)
    {
    
    
        while( q.size()>1 )
        {
    
    
            int x=q.front();
            q.pop_front();
            if( x> q.front() )
            {
    
    
                boo=0;
                break;
            }
        }
    }
    else
    {
    
    
        while( q.size()>1 )
        {
    
    
            int x=q.front();
            q.pop_front();
            if( x< q.front() )
            {
    
    
                boo =0;
                break;
            }
        }
    }
    if(boo )   cout<<"yes\n"<<k;
    else cout<<"no\n";
}

猜你喜欢

转载自blog.csdn.net/m0_53688600/article/details/113847706