牛客竞赛 22148-小a的排列(模拟)

博客针对牛客22148小a的排列这一模拟题给出题解。题目给出长度为n的序列及数字x、y,需找出包含x、y且排序后相邻元素差值为1的区间。因输入是排列,可理解为连续序列打乱顺序。解题利用pos数组维护数字下标,设置边界和最值,通过模拟扩展区间求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

–>题目传送门<–
题意:
给出一个长度为n的序列,和数字x,y。找出包含x,y的区间,并且区间经过排序后,相邻元素差值为1。题目保证输入是一个排列。
题解:
这道题目是一个模拟题,但是绝对不能暴力模拟。
由于输入保证是一个排列,所以可以理解为输入为一个连续的序列,被打乱了顺序。
这道题目的话可以理解为输入的数字为1~n,并且保证每个数字出现且仅出现一次。

以下为解题方法:
利用一个pos数组维护每个数字出现的下标:例 a[1]=2,那么pos[2]=1。
再设置l,r:为当前选取的区间的左右边界
设置mn,mx:分别为当前选取的区间[l,r]内的最小值和最大值。
如果能够满足题意,那么一定满足mx-mn=r-l。

剩下的就是模拟了:
根据x和y的位置初始化L,R。再根据L,R初始化mn,mx。
之后不断的扩展当前选取的区间,再根据区间不断更新mn和mx。
直至满足题意:也就是当前区间[l,r]内的所有值就是[mn,mx]。

AC 代码:

#include <bits/stdc++.h>

using namespace std;

#define LL long long

const int maxn=1e5+5;
int a[maxn],pos[maxn];
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0);
   	cout.tie(0);
    int n,x,y;
    cin>>n>>x>>y;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        pos[a[i]]=i;
    }
    int L=pos[x],R=pos[y];//初始化
    if(L>R)swap(L,R);//保证有序性

    //以下为初始化
    int mx=-1,mn=1e7+5,l=L,r=R;
    for(int i=L;i<=R;i++) mn=min(mn,a[i]),mx=max(mx,a[i]);
    for(int i=mn;i<=mx;i++) l=min(l,pos[i]),r=max(r,pos[i]);

    //开始模拟
    while(l<L||R<r)//如果上一个区间不能够满足根据mnmx扩充的新区间那么继续扩充L,R
    {
        int tmn=mn,tmx=mx;

        //根据左右边界扩展mn,mx
        while(l<L)tmn=min(tmn,a[--L]),tmx=max(tmx,a[L]);
        while(R<r)tmn=min(tmn,a[++R]),tmx=max(tmx,a[R]);

        //根据mn、mx扩展左右边界
        for(int i=tmn;i<=mn;i++)l=min(l,pos[i]),r=max(r,pos[i]);
        for(int i=mx;i<=tmx;i++)l=min(l,pos[i]),r=max(r,pos[i]);

        //更新
        mx=tmx,mn=tmn;
    }

    cout<<l<<" "<<r;
	return 0;
}

欢迎评论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值