如题,ABC272 E的题解。
题意:
给出数组A[]
,
执行M次以下操作:
对于每个 A[i]
, 令 A[i] = A[i] + i
。
求每次操作后A[]中的MEX。
分析:
由于求MEX,对于每一次操作后,显然派上用场的只有大小在 0~n 的数。
那么考虑用这些数进行暴力。
下证:该算法时间复杂度为
O
(
n
log
n
)
O(n\log n)
O(nlogn)
要使一个数尽可能多地被处理,它应该尽量小以尽可能减缓大小被增加到 n 以上。但又要大于等于0来发挥作用。
那么最坏序列就是全0的序列。 以N=5为例。
未进行:0 0 0 0 0
第一次:1 2 3 4 5
第二次:2 4 6 8 10
第三次:3 6 9 12 15
容易发现,第一次后数列为 1 ~ n ,第二次后为 2 ~ 2n, 第三次为3~3n。
所以总数为
N
+
N
/
2
+
N
/
3
+
N
/
4
+
.
.
.
N + N/2 + N/3 + N/4 +...
N+N/2+N/3+N/4+... 这是 nlogn 的,(不懂自行百度)。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
for(auto &v : a) cin >> v;
vector<vector<int>> vals(m + 1);
for(int i = 0; i < n; i++) {
if(a[i] >= n) continue;
int l = (a[i] >= 0 ? 1 : (-a[i] + i) / (i + 1));
int r = min(m + 1, (n - a[i] + i) / (i + 1));
for(int j = l; j < r; j++) {
vals[j].push_back(a[i] + (i + 1) * j);
}
}
for(int i = 1; i <= m; i++) {
int sz = vals[i].size();
vector<bool> exi(sz + 1);
for(auto v : vals[i]) {
if(v < sz) exi[v] = true;
}
int res = 0;
while(exi[res]) res++;
cout << res << endl;
}
}