牛客8409H - Equivalent Prefixes
题意
- 给出两个长为 n 的数组 ai,bi,求最大的前缀 q(1≤q≤n) 满足其任意子区间的 RMQa(l,r)=RMQb(l,r),其中 l≤r≤q。
- RMQw(l,r) 指 wl,wl+1,…,wr 中最小值的下标。
- 保证 ai 中和 bi 中的数字两两不同。
思路
- 观察样例可得,对于一段合法的前缀,首先需要保证 ai 和 bi 中相邻元素的大小变化情况相同。
- 仅仅是上面的条件是不够的,来看一组数据:
7
5 1 6 2 4 3 9
5 1 6 3 4 2 9
- 如果仅依据上面的这一个条件,得出的答案是 7,实际的答案是 5。
- 考虑单调栈。
- 我们知道,一个单调上升的单调栈,插入一个数字,如果该数字会影响到区间的最小值,一定有弹栈的操作。
- 因此,维护两个单调上升的单调栈,对于某个 i,如果 stacka.size=stackb.size,那么 ans=i−1。
代码
#include <cstdio>
#include <iostream>
#include <stack>
const int N = 1e6+10;
using namespace std;
stack<int> stk1, stk2;
int ai[N],bi[N];
int n;
void Sol()
{
while(!stk1.empty())stk1.pop();
while(!stk2.empty())stk2.pop();
for (int i=1; i<=n; i++)
{
while (!stk1.empty() && ai[stk1.top()]>=ai[i])
stk1.pop();
while (!stk2.empty() && bi[stk2.top()]>=bi[i])
stk2.pop();
stk1.push(i);
stk2.push(i);
if(i>=2 && (ai[i]>ai[i-1])!=(bi[i]>bi[i-1]))
{
printf("%d\n",i-1);
return;
}
if(stk1.size()!=stk2.size())
{
printf("%d\n",i-1);
return;
}
}
printf("%d\n",n);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for (int i=1; i<=n; i++)
{
scanf("%d",&ai[i]);
}
for (int i=1; i<=n; i++)
{
scanf("%d",&bi[i]);
}
Sol();
}
return 0;
}