codeforces-#615-D

codeforces-#615-D

D. MEX maximizing

题意
给出一个空的数组
每次向里加入一个数yi共加入q次(q<4e5)
你可以通过向数组中任意数字+x或-x任意次使得该数列中的MEX的值尽可能的大
每次加入一个数后询问该数组的mex
对于数组[0,0,1,0,2],MEX = 3,因为数字0、1和2在数组中表示,而3是数组中未表示的最小非负整数;

题解

不难发现+x -x的性质实际上让新加入的数yi等效转化成加入一个yi%x,统计cnt[yi%x]++;
那么对于这个数组的MEX实际就是求得从0到x-1中cnt[i]最少的数 那么MEX=最少的这个数i+x*cnt[i]
此处用线段树维护0到x-1内cnt[i]的最小值

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
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO std::ios::sync_with_stdio(false);
#define endl '\n'
const int maxn=(int)4e5+5;
int num[(int)4e5+5];
struct Tree{
int L,R;
int minn;
int minn_num;
}tree[maxn<<2];
inline void push_up(int i){
tree[i].minn=min(tree[i<<1].minn,tree[i<<1|1].minn);
if(tree[i<<1].minn==tree[i<<1|1].minn){
tree[i].minn_num=min(tree[i<<1].minn_num,tree[i<<1|1].minn_num);
}
else if(tree[i].minn==tree[i<<1].minn){
tree[i].minn_num=tree[i<<1].minn_num;
}
else tree[i].minn_num=tree[i<<1|1].minn_num;
return ;
}
void build(int L,int R,int i){
tree[i].L=L;tree[i].R=R;
if(L==R){
tree[i].minn=0;
tree[i].minn_num=L;
return ;
}
int mid=(L+R)>>1;
build(L,mid,i<<1);
build(mid+1,R,i<<1|1);
push_up(i);
return ;
}
void updata(int dis,int i){
if(tree[i].L==tree[i].R){
tree[i].minn++;
///cout<<tree[i].minn_num<<" "<<tree[i].minn<<endl;
return ;
}
if(dis<=tree[i<<1].R)updata(dis,i<<1);
else if(dis>=tree[i<<1|1].L)updata(dis,i<<1|1);
push_up(i);return;
}
int main() {
int q,x;cin>>q>>x;
build(0,x-1,1);
for(int i=0;i<q;i++){
int c;cin>>c;
num[c%x]++;
updata(c%x,1);
int ans=tree[1].minn_num;
//cout<<ans<<endl;
cout<<ans+x*num[ans]<<endl;
}
}

但可以用更简单的方法

1
2
3
4
5
6
7
8
9
10
int now=0;
for(int i=0;i<q;i++){
int c;cin>>c;
cnt[c%x]++;
while(cnt[now%x]){
cnt[now%x]--
now++;
}
cout<<now<<" ";
}