思路:虽然a[i]的范围比较大(1e9), 但关心的只是mex的值,所以mex的值最大为n,为5e3,先进行预处理,找到初始的mex(a), 设为pos,那么pos之后的值就不用管了。进行动态规划,f[i][j]表示在前i个数中(0 ~ i), 当前mex为j的最小m值。
状态转移:
1、先不删除i,f[i][j] = f[i - 1][j]
2、删除i,f[i][j] = f[i - 1][i] + (cnt[i] - 1) * j
取min即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6 + 5, inf = 1e9, maxm = 5e3 + 5;
int a[maxn];
int suf[maxn];
int f[maxm][maxm];
string s;
int n, m;
map<int, int> mp;
int cnt[maxm];
void solve()
{
cin >> n;
for(int i = 1; i <= n; i++){
cnt[i] = 0;
}
mp.clear();
for(int i = 1; i <= n; i++){
cin >> a[i];
mp[a[i]]++;
}
int pos;
int tot = 0;
for(int i = 0; i <= n; i++){
if(!mp[i]){
pos = i;
break;
}
cnt[i] = mp[i];
tot += cnt[i];
}
pos--;
for(int i = 0; i <= pos; i++){
for(int j = 0; j <= pos + 1; j++){
f[i][j] = inf;
}
}
for(int j = 1; j <= pos + 1; j++){
f[0][j] = (cnt[0] - 1) * j;
}
for(int i = 1; i <= pos; i++){
for(int j = i + 1; j <= pos + 1; j++){
f[i][j] = min(f[i - 1][j], f[i - 1][i] + (cnt[i] - 1) * j + i);
// cout << i << ' ' << j << ' ' << f[i][j] << '\n';
}
}
cout << f[pos][pos + 1] << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}