G-小a的排列

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

题目描述
小a有一个长度为n的排列。定义一段区间是"萌"的,当且仅当把区间中各个数排序后相邻元素的差为1
现在他想知道包含数x,y的长度最小的"萌"区间的左右端点
也就是说,我们需要找到长度最小的区间[l,r],满足区间[l,r]是"萌"的,且同时包含数
x和数y
如果有多个合法的区间,输出左端点最靠左的方案。

输入描述:
第一行三个整数N,x,y,分别表示序列长度,询问的两个数
第二行有n个整数表示序列内的元素,保证输入为一个排列
输出描述:
输出两个整数,表示长度最小"萌"区间的左右端点

示例1
输入
5 2 3
5 2 1 3 4
输出
2 4
说明
区间[2,4]={2,1,3}包含了2,3且为“萌”区间,可以证明没有比这更优的方案
示例2
输入
8 3 5
6 7 1 8 5 2 4 3
输出
5 8
备注:
保证2⩽n⩽10^5,1⩽x,y⩽n

思路:
这道题乍一看很唬人,但是当你读完题目之后,你会发现:“诶嘿,怎么肥四?如果区间很“萌”,辣么区间的数的首尾之差就等于它们序数的首尾之差,这道题原来可以直接贪心的嘛~”好啦,话不多说,上思路
1、首先输入一个含有n个数的序列,保存到数组a里(保证是一个排列,也就是说题目一定有解)。
在输入的序列中,你可以寻找x和y的位置并记录下来(我用的是l和r)。因为x和y这两个数必须在区间里,所以它们中间的数一定也在区间里,然后把从a[l]到a[r]从小到大排列开来。
2、然后判定一下首数和尾数的差与它们的序数的差是否相等,即(r-l)是否等于(a[r]-a[l])(此时已经按从小到大的顺序排好了)。要是不等,就从给定的序列两端开始,查找
处于a[l]和a[r]之间的数。
3、然后把更新l和r的位置,并将新的a[l]~a[r]排序
4、若(r-l)=(a[r]-a[l])则输出l、r;若(r-l)!=(a[r]-a[l])则重复2、3、4步。

代码

 #include
using namespace std;
int main()
{
	int n,i,x,y,l,r,z,a[100005]={0},l1,r1;//l,r记录位置l1,r1用来搜a[l]~a[r]间的数
	scanf("%d%d%d",&n,&x,&y);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if(a[i]==x)
		{
			l=i;//记录位置
		}
		if(a[i]==y)
		{
			r=i;//记录位置
		}
	}
	if(l>r)//若前后颠倒,交换
	{
		z=l;
		l=r;
		r=z;
	}
	sort(a+l,a+r+1);//排序
	while((r-l)!=(a[r]-a[l]))
	{
		l1=1;r1=n;
		while(l1<l&&(a[l1]<a[l]||a[l1]>a[r]))
			l1++;//找最左边存在区间内的数
		while(r1>r&&(a[r1]<a[l]||a[r1]>a[r]))
			r1--;//找最右边存在区间内的数
		l=l1;r=r1;//更新首尾
		sort(a+l,a+r+1);//排序
	}
	printf("%d %d",l,r);
	return 0;
}

你可能感兴趣的:(G-小a的排列)