Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
For a fixed permutation, an interval has mex exactly when it contains the positions of and does not contain the position of .
You never need to fight for a missing mex bigger than . If value is placed between values and , then every interval containing both and also contains , so mex cannot appear.
So the real job is only checking whether answer mex is possible, then whether answer mex is possible. If both fail, force mex to be missing with the trick.
Mex is missing iff every given interval contains the position of . That means all intervals must share at least one common point.
Mex is missing iff every interval containing also contains . This can be done with adjacent positions: put at and at if no interval ends at , or put at and at if no interval starts at .
Think in positions, not values.
Let be the position of value in the permutation. For any interval , we have:
That already tells us almost the whole problem. The interval values are just wearing fake mustaches; the positions are what matter.
A Universal Upper Bound: We Can Always Make Mex Missing
Place the values so that lies between and in the array, for example:
at three consecutive positions.
Any contiguous interval containing both and must also contain everything between them, including . Therefore no interval can contain and while excluding .
So mex never appears in .
That means the optimal answer is always one of . Nice. We only need to check whether we can do better than .
When Is Mex Missing?
Mex appears if some interval does not contain .
So mex is missing iff every interval contains .
That is possible exactly when all intervals have a common point. If
then the common intersection is nonempty iff .
If this happens, place anywhere in and fill the rest arbitrarily. Then every interval contains , so no interval has mex , and the minimum possible is . You can't beat zero, obviously.
When Is Mex Missing?
Now suppose mex is impossible to remove. Then no matter where we place , some interval misses it, so mex appears.
To make , we need mex to be missing. Mex appears when an interval contains but misses .
So we need:
Every interval containing must also contain .
How can we force that?
Put at position and at position .
An interval containing but not must end exactly at . Therefore, if no interval ends at , then every interval containing also contains .
Similarly, put at position and at position .
An interval containing but not must start exactly at . Therefore, if no interval starts at , then every interval containing also contains .
So scan every adjacent pair :
If either case works, mex is missing, and since mex is already unavoidable, this is optimal.
If Mex and Mex Both Fail
Then the answer must be .
Use the universal construction:
Then mex is missing because every interval containing positions and also contains position .
We also need mex and mex to appear:
So and , giving .
Algorithm
For each test case:
start[x]: whether some interval starts at ,finish[x]: whether some interval ends at ,0 there.finish[i] == false, place 0,1 at i,i+1;start[i+1] == false, place 1,0 at i,i+1.0,2,1 at positions 1,2,3.Correctness Proof
We prove the construction minimizes .
First, for any interval, mex depends only on whether the interval contains the positions of . In particular, mex depends only on , mex only on and , and mex only on .
If all intervals share a common point and we put there, every interval contains . Thus no interval has mex , so . This is optimal.
If the intervals do not share a common point, then for every possible position of , at least one interval misses it. That interval has mex . Therefore mex is unavoidable, and the answer cannot be .
For mex to be missing, every interval containing must also contain .
If we place at and at , this condition fails exactly when some interval ends at . So if no interval ends at , mex is missing.
If we place at and at , this condition fails exactly when some interval starts at . So if no interval starts at , mex is missing.
Conversely, suppose mex can be missing with at position and somewhere else. If is to the right of , then no interval can end at , or that interval would contain and miss . Then the adjacent placement at would also work. If is to the left of , then no interval can start at , and the adjacent placement at would work. Therefore the scan finds a mex- construction iff one exists.
If the scan succeeds, mex is unavoidable and mex is missing, so the answer is optimally .
If the scan fails, mex is impossible to remove. Then we use positions as . Any interval containing both and must contain , so mex is missing. Since mex and mex are both unavoidable, the resulting mex of is exactly , which is optimal.
Therefore the algorithm always outputs an optimal permutation.
Complexity
Everything is one pass over intervals plus one pass over positions:
per test case.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
vector<int> starts(n + 2, 0), ends(n + 2, 0);
int commonL = 1, commonR = n;
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
starts[l] = 1;
ends[r] = 1;
commonL = max(commonL, l);
commonR = min(commonR, r);
}
vector<int> ans(n + 1, -1);
auto fillAndPrint = [&]() {
vector<int> used(n, 0);
for (int i = 1; i <= n; i++) {
if (ans[i] != -1) used[ans[i]] = 1;
}
int x = 0;
for (int i = 1; i <= n; i++) {
if (ans[i] == -1) {
while (used[x]) x++;
ans[i] = x;
used[x] = 1;
}
}
for (int i = 1; i <= n; i++) {
if (i > 1) cout << ' ';
cout << ans[i];
}
cout << '\n';
};
if (commonL <= commonR) {
ans[commonL] = 0;
fillAndPrint();
continue;
}
bool done = false;
for (int i = 1; i < n && !done; i++) {
if (!ends[i]) {
ans[i] = 0;
ans[i + 1] = 1;
done = true;
} else if (!starts[i + 1]) {
ans[i] = 1;
ans[i + 1] = 0;
done = true;
}
}
if (done) {
fillAndPrint();
continue;
}
ans[1] = 0;
ans[2] = 2;
ans[3] = 1;
fillAndPrint();
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
vector<int> starts(n + 2, 0), ends(n + 2, 0);
int commonL = 1, commonR = n;
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
starts[l] = 1;
ends[r] = 1;
commonL = max(commonL, l);
commonR = min(commonR, r);
}
vector<int> ans(n + 1, -1);
auto fillAndPrint = [&]() {
vector<int> used(n, 0);
for (int i = 1; i <= n; i++) {
if (ans[i] != -1) used[ans[i]] = 1;
}
int x = 0;
for (int i = 1; i <= n; i++) {
if (ans[i] == -1) {
while (used[x]) x++;
ans[i] = x;
used[x] = 1;
}
}
for (int i = 1; i <= n; i++) {
if (i > 1) cout << ' ';
cout << ans[i];
}
cout << '\n';
};
if (commonL <= commonR) {
ans[commonL] = 0;
fillAndPrint();
continue;
}
bool done = false;
for (int i = 1; i < n && !done; i++) {
if (!ends[i]) {
ans[i] = 0;
ans[i + 1] = 1;
done = true;
} else if (!starts[i + 1]) {
ans[i] = 1;
ans[i + 1] = 0;
done = true;
}
}
if (done) {
fillAndPrint();
continue;
}
ans[1] = 0;
ans[2] = 2;
ans[3] = 1;
fillAndPrint();
}
return 0;
}