题目大意
给定两个长度为n的数组,求最大的p,使得1到p以内的所有子区间的对应的最小值的位置相同。
原题目链接https://ac.nowcoder.com/acm/contest/881/A
思路:
首先遍历两个数组,记录每个数组元素左边第一个小于当前数组元素值的位置pos[i]。
再从左到右遍历一遍两个pos数组,记录下第一个posA[i]和posB[i]结果不同的地方,该位置前一个位置就是答案。
思路证明:
对于当前元素的位置i,我们记录的其左边第一个小于当前元素值的位置pos,那么对于(pos,i),(pos+1,i)… (i,i)是符合题目条件的。
如果pos左侧的值都比pos处的值要大,那么显而易见,(1,i),(2,i),…,(pos-1,i)也是符合题意的。
如果pos左侧的值有的比pos处的值小,那么从左往右数,第一个比pos小的值的位置pos2,(pos2,pos1),(pos2+1),…,(pos,pos)是符合题意的,再从pos2开始考虑,用类似递归的思想,很容易明白,(1,i),(2,i),…,(pos-1,i)都是符合题意的。
这是右端点是i的情况,但是因为i从左向右遍历,所以之前的所有区间其实都已经检测过了。
AC代码如下
#include <iostream>
#include <stack>
using namespace std;
int a[100005],b[100005],posA[100005],posB[100005];//定义位置数组posA,posB
int main(){
int n;
while(cin>>n){
//作为栈底元素用于收割
a[0]=-1,b[0]=-1;
//输入
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
stack <int> sta,stb;
sta.push(0),stb.push(0);
//记录每个数组元素左边第一个小于当前数组元素值的位置pos[i]
for(int i=1;i<=n;i++){
while(a[sta.top()]>a[i])
sta.pop();
posA[i]=sta.top();
sta.push(i);
while(b[stb.top()]>b[i])
stb.pop();
posB[i]=stb.top();
stb.push(i);
}
//再从左到右遍历一遍两个pos数组,记录下第一个posA[i]和posB[i]结果不同的地方
int p=1;
for(int i=1;i<=n;i++){
if(posA[i]==posB[i])
p=i;
else
break;
}
cout<<p<<endl;
}
return 0;
}
另外一种比较暴力的思路:
{1,2,3}的子区间对于{1,2,3,4}的子区间而言只多了(3,4),(2,3,4),(1,2,3,4)这几个区间,也就是(1,i),(2,i),(3,i)所以按照这个思路,遍历数组进行判断就可以。
AC代码如下
#include <iostream>
using namespace std;
int a[100010],b[100010];
int main(){
int n,p,i,ans,pos;
while(cin>>n){
ans=n;
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=n;i++)
cin>>b[i];
for(p=1;p<=n;p++){
pos=1;
for(i=p-1;i;i--){
if((a[p]>a[i]&&b[p]<b[i])||(b[p]>b[i])&&a[p]<a[i]){
pos=0;
break;
}
if((a[p]>a[i])&&(b[p]>b[i])){
break;
}
}
if(!pos){
ans=p-1;
break;
}
}
cout<<ans<<endl;
}
return 0;
}
参考博客:
http://www.manongjc.com/detail/8-szmegimpjimowzk.html