Codeforces Round 1120 (Div 2) - C1. Floor of MEX (Easy Version)
C1. Floor of MEX (Easy Version)
time limit per test: 2 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard output
This is the easy version of the problem. The difference between the versions is that in this version, you only need to find one subset that satisfies the constraints. You can hack only if you solved all versions of this problem.
Let
where is a set of non-negative integers and is a positive integer.
Farmer John chooses a (possibly empty) subset . He then constructs an array of length , where for every .
Bessie, being a mischievous cow, hides the set . Farmer John is left only with the array .
Your task is to construct any (possibly empty) subset such that for every . Farmer John will only give you arrays where such a exists.
denotes the minimum excluded (MEX) of the collection . (in this case, the minimum non-negative integer not present in the set)
Input
Each test contains multiple test cases. The first line contains the number of test cases (). The description of the test cases follows.
The first line of each test case contains a single integer ().
The second line of each test case contains integers ().
You will only be given arrays where there exists such that for every .
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, output two lines.
On the first line, output an integer — the size of the set .
On the second line, output distinct integers — the elements of . If , the second line should be empty.
The elements of may be printed in any order.
If there are multiple solutions, you may output any of them.
Example
Input
3
6
0 3 2 2 2 1
5
2 1 1 1 1
6
1 2 1 1 1 1
Output
5
1 2 3 4 5
2
0 1
2
0 2
Note
For the first test case, one possible answer is
Then
and
Finally,
Thus the array is .
For the second test case, one possible answer is
Then , and for every , we have
so . Therefore, the array is .
这是一道非常精妙但结论极其优美的构造题。
题解
1. 问题分析与 性质
根据题意,对于每个 ,均有:
由 (最小未出现的非负整数)的定义,上述条件等价于以下两点:
- 必须包含:对每一个整数 ,集合 中至少存在一个元素 使得 。
- 绝对不能包含:集合 中不能存在任何元素 使得 。
2. 禁选区间
从条件 2 出发,满足 的整数 满足:
这意味着对于每个 ,区间 中的所有元素都不能放入集合 中。
我们记所有这些被禁止的元素的并集为 :
任何合法的集合 都必然满足 。
3. 贪心构造:选取最大可能集合
题目保证至少存在一个合法的解 。
由于 是合法的, 也必须避开所有禁止的区间,因此必有:
此时,我们直接构造集合 为所有未被禁止的元素的全集:
显然有 。我们来验证这样的 是否对所有 都成立:
- 上界限制: 中没有任何元素来自禁选集合 ,因此对任意 ,都有 ,即 。
- 下界覆盖:因为 ,所以: 由于已知 是合法的解, 已经覆盖了 中的所有值,因而包含关系更大的 必然也覆盖了 中的所有值。
结合以上两点,对于每个 , 计算出的 恰好就是 !
因此,只需将所有禁选区间覆盖的数剔除,剩下的数构成的集合即为一组正确答案。
4. 算法实现与复杂度
- 对于每个 ,如果 ,则区间 为禁选区间。注意 可能会超过 32 位整数范围,需要用 64 位整数(
long long)防止溢出。 - 使用差分数组(Difference Array)快速对这些区间进行区间加 1 操作。
- 通过一次前缀和计算每个位置被覆盖的次数,未被任何禁选区间覆盖的位置即为集合 的元素。
- 单组数据时间复杂度为 ,总时间复杂度为 ,空间复杂度为 。
C++ 代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void solve() {
int n;
cin >> n;
vector<long long> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// 差分数组标记每个被禁止的位置
vector<int> diff(n + 2, 0);
for (int k = 1; k <= n; k++) {
long long L = 1LL * k * a[k];
if (L < n) {
long long R = min((long long)n - 1, L + k - 1);
diff[L]++;
diff[R + 1]--;
}
}
// 通过前缀和找出所有未被禁止的位置
vector<int> B;
int cur = 0;
for (int y = 0; y < n; y++) {
cur += diff[y];
if (cur == 0) {
B.push_back(y);
}
}
// 输出集合大小
cout << B.size() << "\n";
// 输出集合元素
for (int i = 0; i < (int)B.size(); i++) {
cout << B[i] << (i + 1 == (int)B.size() ? "" : " ");
}
cout << "\n";
}
int main() {
// 快速 I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}