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;
}

深深地感到自己的弱小。

posted @ 2020-10-17 21:51  syzf2222  阅读(97)  评论(0编辑  收藏  举报