想了很久没弄明白,对于边界的情况还是有问题
等题解出了再看看
然后枚举每个后缀r,找到比它小,并且在其左边的前缀l,那么删<=l,r-1的都可以
最后的二分很迷:要多考虑特殊情况:前缀跑到后缀后面去了,那么在后缀后面加一个x+1,保证前缀必定在后缀前面
#include <iostream> #include <algorithm> #include <cstring> #include <vector> using namespace std; typedef long long LL; const int N = 1000000 + 10; int n,x,a[N]; int L[N],R[N]; int pre[N],suf[N]; int main() { for(int i=0;i<N;i++){ L[i]=N,R[i]=0; } scanf("%d%d",&n,&x); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); L[a[i]]=min(L[a[i]],i); R[a[i]]=max(R[a[i]],i); } int prelen=0,suflen=x+1; for(int i=1;i<=x;i++){ if(R[i]==0) pre[++prelen]=pre[prelen-1]; else { if(L[i]>pre[prelen]) pre[++prelen]=R[i]; else break; } } suf[suflen]=n+1; for(int i=x;i>=1;i--){ if(R[i]==0){ suf[suflen-1]=suf[suflen]; --suflen; } else { if (R[i]<suf[suflen]) { suf[suflen-1]=L[i]; --suflen; } else { break; } } } LL ans=0; for(int i=x+1;i>=max(suflen,2);i--) { // use [i,x] int lef=0,rig=min(i-2,prelen)+1; while(rig-lef>1){ int mid=(lef+rig)>>1; if(pre[mid]<suf[i]){ lef=mid; } else { rig=mid; } } ans=ans+(lef+1); } cout<<ans<<endl; }