–>题目传送门<–
题意:
给出一个长度为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;
}
欢迎评论!