CF1139E Maximize Mex
孤立地去看每一个询问,发现问题可以这样转化:
有一些集合,取出一个数则集合占用,求最多可以取多少个从0开始的连续自然数。
先手玩一组数据:
\(\{0,1,2\},\{1,2,3\},\{1,3\}\)
考虑0:占用\(\{0,1,2\}\)
考虑1:占用\(\{1,2,3\}\)
考虑2:发现有2的\(\{1,2,3\}\)已经被占用,且占用此集合的1也可以选择\(\{1,3\}\),则2抢过\(\{1,2,3\}\),把\(\{1,3\}\)给1
考虑3:无法匹配
发现此过程类似于二分图匹配。
将\(\{0,1,2,3...\}\)去匹配每一个集合,集合中包含此数则连边。
那么这样得到一个\(\Theta(dnm)\)的优秀算法,\(TLE\)在第十个点。
考虑优化。
因为一个人走之后就不会再回来,考虑倒序处理。
加入一个人之后,易知答案只增不减,故复杂度降低为\(\Theta(dm)\)。
代码仅供参考:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,d,p[maxn],c[maxn],ans[maxn];
int beg[maxn],nex[maxn],to[maxn],e;
inline void add(int x,int y){
e++;nex[e]=beg[x];
beg[x]=e;to[e]=y;
}
int mat[maxn],vis[maxn],pro[maxn],out[maxn];
inline int dfs(int x){
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(vis[c[t]]||out[t])continue;
vis[c[t]]=1;
if(mat[c[t]]==-1||dfs(mat[c[t]])){
mat[c[t]]=x;
return 1;
}
}
return 0;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
p[i]=read();
add(p[i],i);
}
for(int i=1;i<=n;i++)
c[i]=read();
d=read();
for(int i=1;i<=d;i++){
pro[i]=read();
out[pro[i]]=1;
}
memset(mat,-1,sizeof(mat));
for(int i=d;i>=1;i--){
for(int j=ans[i+1];;j++){
memset(vis,0,sizeof(vis));
if(!dfs(j)){ans[i]=j;break;}
}
out[pro[i]]=0;
}
for(int i=1;i<=d;i++)
printf("%d\n",ans[i]);
return 0;
}
深深地感到自己的弱小。