codeforces-#678-E

codeforces-#678-E

十一月 14, 2020

E. Complicated Computations

  • 题意

给出一个长度为n<1e5的数组a

求出它所有子串的MEX组成的新数组b的MEX

对于一个给定数组 其MEX是 最小的不出现在数组中的正数

  • 题解

参考博客

如 数组a为1 3 2

数组b为 2 2 4 1 1 1

所以答案为3

首先要求出所有子串的MEX 而n为1e5 显然 暴力求解出b数组不可取

但是存在一个事实:对于一个数组 若去除其中重复的数字 剩下 的数组成的MEX

仍然与原来相同

那么我们不需要暴力枚举出所有a的子串求得其MEX

反过来想 我们只需要判断某个数x是否会是某个a的子串的MEX

于是我们枚举x (1~n+1) 每次判断是否存在一个a的子串它的MEX=x

若存在 那么数组b中加入 x 最终答案则直接求b的MEX

如果一个区间的MEX=x,那么容易发现只需满足如下条件 :

  • 区间中没有出现x
  • 区间中出现了1到x−1

    于是 考虑枚举每个以x为端点的子段

比如…. x (1 4 2 4 6) x ….

MEX=x的子段不会出现在一个包含x的子串中 于是满足条件一

对于第二个条件 维护一个权值线段树

以权值为点 存对应数在原数组中出现的最后位置

因为要确保 两个x 之间存在1到x-1所有数

所以只需要确保 (1,x-1)所以有数最后一次出现的位置在 两个x之间

若符合条件那么 显然 a中存在子串MEX=x 那么x被加入b数组

我们枚举可能存在的MEX=x

判断区间…. x (1 4 2 4 6) x …. 的MEX而不是 …. x (1 4 2) 4 6 x ….的MEX

为什么后者不需要枚举? 首先我们是在判断x是否会成为a的子串的MEX

于是我们找最有可能出现MEX=x的子串 即夹在两个x之间的子段

他们不包含x且元素最多最有可能包含(1,x-1)所有数

从而减小了暴力枚举a的子串的复杂度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
//#define P pair<ll,ll>
const int Max=2e5+5;
const int Mod=998244353;
const int inf=0x3f3f3f3f;


#define __DEBUG__
#ifdef __DEBUG__
#define DeBug(format, ...) \
{ \
fprintf(stdout, "\[%s:%d] \" format " ", \
__FUNCTION__ , __LINE__, ##__VA_ARGS__); \
}
#else
#define DeBug(format,...)
#endif

/*

*/
class SegTree{
public:
#define mid ((L+R)>>1)
#define Leftson now<<1
#define Rightson now<<1|1
struct segtree{int L,R,pos;};
segtree tree[Max<<2];
void push_up(int now){
tree[now].pos=min(tree[Leftson].pos,tree[Rightson].pos);
return;
}
void build(int L,int R,int now=1){
tree[now]={L,R,0};
//cout<<L<<" "<<R<<endl;
if(L==R)return;
//int mid=(L+R)>>1;
build(L,mid,Leftson);
build(mid+1,R,Rightson);
push_up(now);
return;
}
void updata(int qL,int qR,int val,int now=1){
if(qL<=tree[now].L&&qR>=tree[now].R){
tree[now].pos=val;
return;
}
if(qL<=tree[Leftson].R)updata(qL,qR,val,Leftson);
if(qR>=tree[Rightson].L)updata(qL,qR,val,Rightson);
push_up(now);return;
}
int query(int qL,int qR,int now=1){
if(qL>qR)return inf;
if(tree[now].R<=qR&&tree[now].L>=qL)return tree[now].pos;
int minnpos=inf;
if(tree[Leftson].R>=qL)minnpos=min(minnpos,query(qL,qR,Leftson));
if(tree[Rightson].L<=qR)minnpos=min(minnpos,query(qL,qR,Rightson));
push_up(now);
return minnpos;
}
}Val;
bool vis[Max];
int arr[Max],last[Max];
int main(){
//Turnoff;
int n;cin>>n;
Val.build(1,n);
for(int i=1;i<=n;i++)cin>>arr[i];
for(int i=1;i<=n;i++){
if(arr[i]!=1)vis[1]=1;
if(arr[i]>1&&Val.query(1,arr[i]-1)>last[arr[i]])vis[arr[i]]=1;
last[arr[i]]=i;
Val.updata(arr[i],arr[i],i);
}
for(int i=2;i<=n+1;i++){
if(Val.query(1,i-1)>last[i])vis[i]=1;
}
int Mex=1;
while(vis[Mex])Mex++;
cout<<Mex<<endl;
return 0;
}