题意:题目给定两个序列a,b,规定两个序列若要相等的话,必须满足RMQ(a,l,r)=RMQ(b,l,r),而RMQ(a,l,r)的定义是在a序列中,[l,r]的最小值的下标,即两序列若要相等,则任意相同区间的子串都必须满足最小值下标相等的条件,然后问题是找出a,b序列中最大的r值,使得a[1,r]=b[1,r]
思路:如果我们采取相当粗暴的手段去写这道题,首先想到的可能就从小到大枚举r值,然后check一下,就像下面这样
for (int i = 1; i <=n; ++i){
for (int j = 1; j <i; ++j){
if(mi(j,i)!=mi(j,i)){
ans=i-1;
//cout<<i<<' '<<j<<endl;
goto A;
}
}
}
不过显然易见,这种做法的时间复杂度是n方的,绝对会超时,我们需要想一个优化策略来降低我们的时间复杂度。
首先假设我已经check完了r=i的情况,我们即将要check r=i+1的情况,我们发现如果在这个区间中存在a[j]<a[i+1]的话,[j,i+1],[j-1,i+1],[j-2,i+1],...,[1,i+1]都不用考虑了,因为这些区间的最小值都和a[i+1]没有关系了,在我们check r=i的时候就已经全部check完了,所以我们需要从第i+1个数开始往左找,找第一个小于a[i+1]的数a[j],这样子[j+1,i+1],[j+2,i+1],...,[i+1,i+1]的最小值都是a[i+1],然后我们发现在我们已经验证了r=i是可行的情况下,我们只需要确保r=i+1时的j值一样就行了,所以问题就转化成了r=1,2,3,...,n时j的大小。
接下来就是裸的单调栈了
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn=1e5+9;
struct node{
int val,pos;
};
stack<node>stk;
int a[maxn],b[maxn],lst1[maxn],lst2[maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int i,j,k,n;
while(cin>>n){
for(i=0;i<n;i++){
cin>>a[i];
lst1[i]=i;lst2[i]=i;
}
for(i=0;i<n;i++){
cin>>b[i];
}
for(i=n-1;i>=0;i--){
if(stk.empty()||a[i]>stk.top().val){
stk.push({a[i],i});
}
else{
while(!stk.empty()&&a[i]<stk.top().val){
int pos=stk.top().pos;
lst1[pos]=i;
stk.pop();
}
stk.push({a[i],i});
}
}
while(!stk.empty())stk.pop();
for(i=n-1;i>=0;i--){
if(stk.empty()||b[i]>stk.top().val){
stk.push({b[i],i});
}
else{
while(!stk.empty()&&b[i]<stk.top().val){
int pos=stk.top().pos;
lst2[pos]=i;
stk.pop();
}
stk.push({b[i],i});
}
}
while(!stk.empty())stk.pop();
int ans;
for(i=0;i<n;i++){
if(lst1[i]==lst2[i]){
ans=i;
}
else break;
}
cout<<ans+1<<endl;
}
}