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