题解:P14132 【MX-X22-T3】「TPOI-4C」Another MEX Problem
前置
- 链表
- STL set 的使用
本做法写起来简单,用的知识也是普及组范围内的,请放心阅读。
思路
首先我们理解题意,这里的
对于一些已经出现的数字,我们要添加最多
假设两个相邻的已有数字是
所以我们考虑逐步加入数字的过程,可以维护一个链表表示所有区间,并维护每个区间需要多少数来填充。
加入一个数就相当于在链表某个位置插入这个数。为了找到这个位置,可以使用 set 找到第一个小于这个数的数,并用 unordered_map 找到这个数字在链表中的位置。
然后就可以更新前后两段空隙的“需要填多少个数”。
我们还需要实时维护一个位置
回顾一遍加数过程:
- 找到在链表中的位置;
- 更新链表该位置空隙所需数字;
- 如果所需数字减少了,并且
pos 在加的数后面,就增加可用数字; - 如果可用数字足以让
pos 在链表上的位置更靠后,就更新pos ,减少可用数字。重复。 - 用
pos 和可用数字算出具体的最大\operatorname{mex} 。
时间复杂度
::::info[参考实现]
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T, n, m, k, a[200010], b[200010];
int nxt[200010], val[200010], num[200010];
int tp = 0;
unordered_map<int, int> mp;
set<int> s;
void pres() {
s.clear(), mp.clear();
s.insert(-1), s.insert(1e18);
nxt[1] = 2, val[1] = 1e18;
num[1] = -1, num[2] = 1e18;
mp[-1] = 1, mp[1e18] = 2;
tp = 2;
}
signed main() {
cin >> T;
while (T--) {
pres();
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
int ans = 0, pos = 1, cur = 0;
for (int i = 1; i <= n; i++) {
if(s.find(a[i]) == s.end()){
auto it = s.lower_bound(a[i]);
int l = mp[*--it], r = nxt[l], d = val[l];
s.insert(a[i]);
mp[a[i]] = ++tp, num[tp] = a[i];
val[l] = (a[i] - num[l] - 1) / k, d -= val[l];
val[tp] = (num[r] - a[i] - 1) / k, d -= val[tp];
nxt[l] = tp, nxt[tp] = r;
if (num[pos] >= num[r]) cur -= d;
while (cur + val[pos] <= m)
cur += val[pos], pos = nxt[pos];
ans = num[pos] + (m - cur) * k + 1;
}
cout << ans << " ";
}
cout << endl;
}
return 0;
}
::::