链接:https://ac.nowcoder.com/acm/contest/317/G
来源:牛客网
 

小a有一个长度为n的排列。定义一段区间是"萌"的,当且仅当把区间中各个数排序后相邻元素的差为1
现在他想知道包含数x,y的长度最小的"萌"区间的左右端点

也就是说,我们需要找到长度最小的区间[l,r],满足区间[l,r]是"萌"的,且同时包含数x和数y

如果有多个合法的区间,输出左端点最靠左的方案。

 

 

输入描述:

第一行三个整数N,x,y分别表示序列长度,询问的两个数
第二行有nn个整数表示序列内的元素,保证输入为一个排列

输出描述:

输出两个整数,表示长度最小"萌"区间的左右端点

示例1

输入

复制

5 2 3 
5 2 1 3 4 

8 3 5
6 7 1 8 5 2 4 3

输出

 2 4
 5 8

保证2⩽n⩽,1⩽x,y⩽n

 

首先,一个区间[l, r]是连续区间当且仅当
我们维护出每个数出现的位置,即;表示数x的位置,考虑每次迭带更新答案。
维护四个变量l,r,minn,maxx分别表示当前区间的左右端点,最大最小值
首先找到[,]中的每个数位置的最大最小值来找到下一轮的l,r;
接下来不断扩充当前的l,r,扩充的同时更新minn,maxx,再不断用新的minn,maxx更新l,r,直到找到一段连
续区
当找到第一个满足条件的区间即为长度最小的区间,实际上长度最小的区间的左右端点只有一种方案,
因为两段相交的连续区间的交集也是连续区

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
inline int read()
{
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
void chmin(int &a, int b) {a = (a < b ? a : b);}
void chmax(int &a, int b) {a = (a > b ? a : b);}
int a[maxn],pos[maxn];
int main()
{
    int N,L,R;
    N=read();L=read();R=read();
    for(int i=1;i<=N;i++)a[i]=read(),pos[a[i]]=i;
    L=pos[L],R=pos[R];
    if(L>R)swap(L,R);
    int minn=99999999,maxx=0,l=L,r=R;
    for(int i=L;i<=R;i++)chmin(minn,a[i]),chmax(maxx,a[i]);
    for(int i=minn;i<=maxx;i++)chmin(l,pos[i]),chmax(r,pos[i]);
    while(l<L||R<r)
    {
        int tmin=minn,tmax=maxx;
        while(l<L)chmin(tmin,a[--L]),chmax(tmax,a[L]);
        while(R<r)chmin(tmin,a[++R]),chmax(tmax,a[R]);
        for(int i=tmin;i<=minn;i++)chmin(l,pos[i]),chmax(r,pos[i]);
        for(int i=maxx;i<=tmax;i++)chmin(l,pos[i]),chmax(r,pos[i]);
        minn=tmin;maxx=tmax;
    }
    cout<<l<<" "<<r<<endl;
    return 0;
}