[CF1436E] Complicated Computations
\(\text{Problem}:\)题目链接
\(\text{Code}:\)
易知答案上界为 \(n+2\)。朴素的想法是,从小到大枚举 \(1\) 到 \(n+1\),判断是否在序列的子区间的 \(mex\) 中出现过。
考虑一段区间 \([l,r]\) 的 \(mex\) 为 \(x\),当 \(x=1\) 时,只需存在 \(a_{i}\not=1\) 即可;当 \(x>1\) 时,有性质:
- \(\forall i\in [1,x-1],\sum\limits_{j=l}^{r} [a_{j}=i]\geq 1\)
- \(\sum\limits_{i=l}^{r}[a_{i}=x]=0\)
那么记录下序列中每个 \(x\) 上一次出现的位置 \(pre_{x}\),特殊的,如果 \(x\) 第一次出现,此时 \(pre_{x}=0\)。记当前 \(a_{i}=x\),当 \(x>1\) 时,只需对于 \(\forall j\in [1,x-1]\),\(j\) 在 \(i\) 之前最后一次出现的位置都大于 \(pre_{x}\)。可以用线段树维护区间最小值来解决这个问题,时间复杂度 \(O(n\log n)\),可以通过本题。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=100010;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,a[N],pre[N],Ans[N],mi[N<<2],mx[N<<2];
#define lc (x<<1)
#define rc (x<<1|1)
void UpDate(int pos,int l,int r,int x,int k)
{
if(l==r) { mi[x]=mx[x]=k; return; }
int mid=(l+r)/2;
if(pos<=mid) UpDate(pos,l,mid,lc,k);
else UpDate(pos,mid+1,r,rc,k);
mi[x]=min(mi[lc],mi[rc]);
mx[x]=max(mx[lc],mx[rc]);
}
int Askmi(int u,int v,int l,int r,int x)
{
if(l>=u&&r<=v) return mi[x];
int mid=(l+r)/2,tt=1e9;
if(u<=mid) tt=min(tt,Askmi(u,v,l,mid,lc));
if(v>mid) tt=min(tt,Askmi(u,v,mid+1,r,rc));
return tt;
}
int Askmx(int u,int v,int l,int r,int x)
{
if(l>=u&&r<=v) return mx[x];
int mid=(l+r)/2,tt=0;
if(u<=mid) tt=max(tt,Askmx(u,v,l,mid,lc));
if(v>mid) tt=max(tt,Askmx(u,v,mid+1,r,rc));
return tt;
}
#undef lc
#undef rc
signed main()
{
memset(mi,0x3f,sizeof(mi));
memset(mx,0x3f,sizeof(mx));
n=read();
for(ri int i=1;i<=n;i++) a[i]=read();
for(ri int i=1;i<=n;i++)
{
if(a[i]!=1) Ans[1]=1;
if(a[i]>1&&Askmi(1,a[i]-1,1,n,1)>pre[a[i]]&&Askmx(1,a[i]-1,1,n,1)<i) Ans[a[i]]=1;
UpDate(a[i],1,n,1,i);
pre[a[i]]=i;
}
for(ri int i=1;i<=n;i++) if(Askmi(1,i,1,n,1)>pre[i+1]&&Askmx(1,i,1,n,1)<=n) Ans[i+1]=1;
for(ri int i=1;i<=n+2;i++) if(!Ans[i]) return printf("%lld\n",i)&0;
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。