题目大意
详细题目传送门
给出 \(n\) 和 \(a_1\cdots a_n\),求有多少个区间 \([l,r]\) 满足 \(a_l\cdots a_r\) 是 \(1\) 到 \(r-l+1\) 的排列。
\(a_i\leq n\leq10^6\)
思路
对于 \([l,r]\),要满足
- \(\max_{i=l}^r a_i=r-l+1\)
- \(\forall i,j,a_i\neq a_j\)
可以猜到真正符合条件的区间应该不会很多,又因为区间一定要有且仅有一个 \(1\),所以可以和 \(1\) 的位置考虑。先考虑一个位置 \(i\) 作为区间端点的情况,所以维护对于一个位置 \(i\) 上一个 \(1\) 和下一个 的位置 \(p_i,n_i\)。发现只考虑 \((i,i+\max_{j=i}^{n_i}a_j-1)\) 和 \((i-\max_{j=p_i}^i a_j+1,i)\) 即可。首先这个肯定是对的,但是为什么不会少呢?是因为对于再前面或后面的,如果还有最大值会被前面的左端点也算上,所以不会算漏只会算重。所以现在有不超过 \(2n\) 个区间需要判断第 \(2\) 个条件。
对于这一个条件,一般做数据结构题做多了就会想到就是求 \(\mathrm{mex}(a_l\cdots a_r)\overset{?}{=} r-l+2\)。
区间 \(\mathrm{mex}\) 是不好求的,但是考虑到我们只有 \(2n\) 个区间,所以考虑离线后排序。前缀 \(\mathrm{mex}\) 相对好求,现在考虑如果把 \(a_l\) 删去带来的影响。发现就是可以在下一个 \(a_l\) 之前使用。所以也就是对于 \(m_i\) 表示 \(\mathrm{mex}\in[l,i]\)。我们可以找到 \(f_i\) 表示下一个 \(a_i\) 的位置。于是对于每一次 \(a_l\) 的删除操作,我们可以将 \(m_i\leftarrow \min(m_i,a_l),i\in[l+1,f_l-1]\)。对于一个 \([l,r]\) 判断 \(m_r\overset{?}{=}r-l+2\) 即可。
时间复杂度 \(O(n\log n)\)。
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const ll MAXN=1e6+5;
ll n,a[MAXN];
ll st[MAXN][22],lg[MAXN+5];
ll qm(ll l,ll r){
ll len=lg[r-l+1];
return max(st[l][len],st[r-(1<<len)+1][len]);
}
ll lst[MAXN],pre[MAXN];
struct Qj{
ll l,r;
bool operator<(const Qj&K)const{
if(l==K.l){
return r<K.r;
}
return l<K.l;
}
};
vector<Qj>V,v;
struct node{
ll u,x,tag;
#define lc(u) (u<<1)
#define rc(u) (u<<1|1)
}t[MAXN*4];
void push_down(ll u){
t[lc(u)].tag=min(t[lc(u)].tag,t[u].tag);
t[rc(u)].tag=min(t[rc(u)].tag,t[u].tag);
t[lc(u)].x=min(t[lc(u)].x,t[u].tag);
t[rc(u)].x=min(t[rc(u)].x,t[u].tag);
t[u].tag=1e18;
}
ll mex[MAXN];
void build(ll u,ll l,ll r){
t[u].tag=1e18;
if(l==r){
t[u].x=mex[l];
return;
}
ll mid=(l+r)>>1;
build(lc(u),l,mid);
build(rc(u),mid+1,r);
}
void modify(ll u,ll l,ll r,ll ql,ll qr,ll x){
if(ql<=l&&r<=qr){
t[u].tag=min(t[u].tag,x);
t[u].x=min(t[u].x,x);
return;
}
push_down(u);
ll mid=(l+r)>>1;
if(ql<=mid){
modify(lc(u),l,mid,ql,qr,x);
}
if(mid+1<=qr){
modify(rc(u),mid+1,r,ql,qr,x);
}
}
ll nxt[MAXN],vs[MAXN];
ll query(ll u,ll l,ll r,ll x){
if(l==r){
return t[u].x;
}
push_down(u);
ll mid=(l+r)>>1;
if(x<=mid){
return query(lc(u),l,mid,x);
}
return query(rc(u),mid+1,r,x);
}
bool vv[MAXN];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
rep(i,2,n+5){
lg[i]=lg[i/2]+1;
};
rep(i,1,n){
cin>>a[i];
if(a[i]==1){
lst[i]=i;
}else{
lst[i]=lst[i-1];
}
st[i][0]=a[i];
};
for(int i=n;i>=1;--i){
nxt[i]=vs[a[i]];
if(nxt[i]==0){
nxt[i]=n+1;
}
vs[a[i]]=i;
if(a[i]==1){
pre[i]=i;
}else{
pre[i]=pre[i+1];
}
}
rep(j,1,lg[n]){
for(int i=1;i+(1<<j)-1<=n;++i){
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
};
rep(i,1,n){
if(lst[i]){
ll l=i-qm(lst[i],i)+1,r=i;
if(l>=1){
V.push_back({l,r});
}
}
if(pre[i]){
ll r=i+qm(i,pre[i])-1,l=i;
if(r<=n){
V.push_back({l,r});
}
}
};
if(V.empty()){
cout<<0<<endl;
return 0;
}
sort(V.begin(),V.end());
v.push_back(V[0]);
rep(i,1,ll(V.size()-1)){
if(V[i].l==V[i-1].l&&V[i].r==V[i-1].r){
continue;
}
v.push_back(V[i]);
};
vv[0]=true;
rep(i,1,n){
mex[i]=mex[i-1];
vv[a[i]]=true;
while(vv[mex[i]]){
mex[i]++;
}
};
build(1,1,n);
ll tot=0,ans=0;
rep(i,1,n){
while(tot<ll(v.size())&&v[tot].l==i){
ll l=v[tot].l,r=v[tot].r,val=query(1,1,n,r);
if(val==r-l+2){
ans++;
}
tot++;
}
modify(1,1,n,i+1,nxt[i]-1,a[i]);
};
cout<<ans<<endl;
return 0;
}
来源链接:https://www.cnblogs.com/tanghg/p/18774598/solution-p10833
没有回复内容