1167E - Range Deleting 双指针

题意:给出n个数的序列,并给出x,这n个数的范围为[1,x],f(L,R)表示删除序列中取值为[l,r]的数,问有几对L,R使得操作后的序列为非递减序列
思路:若[l,r]成立,那么[l,r+1],.....,[l,x]都成立,且若[l,r]成立,那么[l+1,r]不成立,不存在[l+1,r-1]成立, 所以可以看出本题区间具有单调性,可以用双指针求解
说明:表示i值的最右边坐标,表示i值的最左边坐标
若f(l,r)成立要满足三个条件
1.
2.
3.
这里可以用类似前缀和的思想把这几个条件预处理处理,然后直接套用双指针即可
Reference:
https://www.cnblogs.com/henry-1202/p/10888691.html (大佬博客)
https://baijiahao.baidu.com/s?id=1615129382322508344&wfr=spider&for=pc (洛谷双指针总结)
https://www.cnblogs.com/xyq0220/p/10875872.html

#include
#define F first
#define S second
#define pii pair
#define pb push_back
#define mkp make_pair
#define all(zzz) (zzz).being(),(zzz).end()
#define pii pair
typedef long long ll;
typedef long long LL;
using namespace std;
const int maxn=1e6+7;
int s[maxn],t[maxn],ss[maxn],tt[maxn],a[maxn],precan[maxn],lastcan[maxn];
bool check(int l,int r){
    return precan[l-1]&&lastcan[r+1]&&ss[r+1]>tt[l-1];
}
int main(){
    int n,x;
    scanf("%d%d",&n,&x);
    memset(s,0x3f3f3f3f,sizeof(s));
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        s[a[i]]=min(s[a[i]],i);
        t[a[i]]=max(t[a[i]],i);
    }

    long long  ans=0;
    for(int i=1;i<=x;i++){
        tt[i]=max(tt[i-1],t[i]);
    }
    ss[x+1]=0x3f3f3f3f;
    for(int i=x;i>=1;i--){
        ss[i]=min(ss[i+1],s[i]);
    }
    precan[0]=1;
    lastcan[x+1]=1;
    for(int i=1;i<=x;i++)precan[i]=precan[i-1]&&(tt[i-1]<s[i]);
    for(int i=x;i>=1;i--)lastcan[i]=lastcan[i+1]&&(ss[i+1]>t[i]);
    int r=1;
    for(int l=1;l<=x;l++){
        if(l>r)r++;
        while(r<x&&!check(l,r))r++;
        if(check(l,r))ans+=x-r+1;
    }
    cout<<ans<<endl;
    return 0;
}
全部评论

相关推荐

11-15 18:39
已编辑
西安交通大学 Java
全村最靓的仔仔:卧槽,佬啥bg呢,本也是西交么
点赞 评论 收藏
分享
牛客771574427号:恭喜你,华杰
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务