其他分享
首页 > 其他分享> > CF1684E MEX vs DIFF

CF1684E MEX vs DIFF

作者:互联网

https://www.luogu.com.cn/problem/CF1684E

*2100,CCH 的题目功能真好用!

考虑 \(DIFF-MEX\),那么要让 \(DIFF\) 尽可能小,\(MEX\) 尽可能大。

考虑我们填了最长值域前缀,那么显然我们的每次操作都是不会更劣的。假如把 \(MEX\) 后的数填到当前钦定前缀空白,那么 \(MEX+1\),假如所选的数出现的次数只有 1,那么就 \(DIFF-1\),否则 \(DIFF\) 不变。所以这个答案一定不会更劣。考虑有可能钦定的前缀中有重复的,显然对答案不会影响,这些重复的数不必要去填别处的空。因为填别处的空会让 \(DIFF+1\),\(MEX+1\),综合起来不会影响答案。干脆就不填了。

考虑 \(MEX\) 最小一定要保证值域上前缀最长,枚举 \([0,n]\) 即可。对于没有出现的就用之后的数填,需要注意的是这里只要判断是否有填的方案即可。假如出现了 \(k+1\) 个空那么第 \(k+1\) 个空就是最大 \(MEX\)。

差不多就做完了。。。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(1e5+5);
map<int,int>mp; 
int n,m,a[N],vec[N];
void solve() {
	cin>>n>>m;
	mp.clear();
	for(int i=1;i<=n;i++) {
		cin>>a[i]; ++mp[a[i]];
	}
	int res=0,num=0,mx=-1;
	for(int i=0;i<n;i++) {
		if(!mp.count(i)) {
			++num;
			if(n-res<num||num>m) {
				mx=i; --num; break ;
			}
			continue ;
		}
		res+=mp[i];
	}
//	cout<<mx<<" "<<num<<'\n';
	if(mx==-1) {
		cout<<"0\n"; return ;
	}
	int tot=0;
	for(auto it=mp.begin();it!=mp.end();++it) {
		if((it->first)>=mx) {
//			cout<<it->first<<" "<<it->second<<'\n';
			vec[++tot]=it->second;
		}
	}
	sort(vec+1,vec+1+tot);
	int nw=tot; res=0;
	for(int i=1;i<=tot;i++) {
		if(res+vec[i]<=num) {
			res+=vec[i]; --nw;
		} else break ;
	}
	cout<<nw<<'\n';
}

signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	int T; cin>>T; while(T--) solve();
	return 0;
}


标签:前缀,CF1684E,res,int,vs,vec,DIFF,MEX
来源: https://www.cnblogs.com/xugangfan/p/16493914.html