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; }