2019牛客暑期多校训练营(第一场)A Equivalent Prefixes

题意:题目给定两个序列a,b,规定两个序列若要相等的话,必须满足RMQ(a,l,r)=RMQ(b,l,r)(1\leq l \leq r \leq n),而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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值