[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;
}
posted @ 2021-02-27 20:25  zkdxl  阅读(68)  评论(0编辑  收藏  举报