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.
Use
The part is fixed because both arrays contain exactly the numbers . So maximizing OR is the same as minimizing the total AND.
Work from high bits to low bits. If every number in the current interval has the same value at bit , then this bit is already forced. It cannot affect which pairing is best, so move to bit .
At the highest bit where the interval splits, the numbers form two consecutive blocks: bit on the left, bit on the right. Pair as many numbers across these two blocks as possible, because a 0 paired with a 1 avoids paying this bit in the AND.
The best cross-pairs are symmetric around the split point : pair
For such a pair , so their lower bits are complements. That kills the AND on all lower bits too. Very convenient. Suspiciously convenient, even.
After taking all possible symmetric cross-pairs, at most one side has leftovers. Those leftover numbers must be paired among themselves, so recurse on that leftover interval with the next lower bit. This gives a clean divide-and-conquer construction.
We need permute the interval against itself to maximize
The first trick is the standard OR-to-AND flip:
Across all pairs, every number in appears once as a fixed value and once as a permuted value, so
is fixed. Therefore maximizing OR is exactly minimizing
So the real problem is: pair numbers so they share as few 1 bits as possible.
Bit-by-bit view
For one bit , a pair contributes to the AND only if both numbers have bit equal to .
If the current interval has some numbers with bit and some with bit , then pairing a zero-bit number with a one-bit number is good: this bit contributes to the OR, but not to the AND.
So at each important bit, we want as many cross-pairs as possible.
The recursive structure
Define solve(l, r, j) to pair every number in the current interval , considering bits from down to .
The recursion maintains this idea: all bits above are already identical inside the current interval, or already forced. So bit has a simple shape inside a contiguous interval: all the 0s come first, then all the 1s.
There are two cases.
Case 1: bit does not split the interval
If every number in has the same bit , this bit does not create any choice.
If all have bit , no pair pays this bit in the AND.
If all have bit , every pair pays this bit in the AND.
Either way, the pairing decision depends only on lower bits, so we call
Case 2: bit splits the interval
Let the split be
where the left block has bit and the right block has bit .
Let
Now pair outward from the boundary:
and so on while both numbers are inside .
For every such pair, if
then
Because is exactly where bit turns from to , the lower bits of and are complements. Also their bit values are opposite. So these pairs have zero AND contribution on bits .
That is as good as it gets. You cannot do better than zero.
Why this is optimal
At bit , suppose the two blocks have sizes and .
You can make at most cross-pairs. Any extra numbers on the larger side must pair among themselves. If the larger side is the 1 side, those extra pairs are forced to pay bit in the AND. If the larger side is the 0 side, they pay nothing for bit .
So pairing as many cross-pairs as possible is mandatory for optimality.
Among those cross-pairs, the symmetric pairing is also optimal because it makes the lower bits complementary, giving zero lower-bit AND for those pairs. No hidden tax, no annoying catch.
After removing all possible cross-pairs, at most one side has leftovers. Those leftovers cannot be paired across bit anymore, so their bit- situation is forced. The only remaining choices are in lower bits, which is exactly the smaller recursive problem.
That proves the divide-and-conquer construction is optimal.
Computing the answer
The recursion directly fills mate[x], the number paired with . Then we compute
by a simple loop.
The recursion has only bit levels, and each level scans/pairs pieces of the interval. With
this is easily fast enough. No need to summon a segment tree for a fistfight.
#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 L, R;
cin >> L >> R;
vector<int> mate(R - L + 1, -1);
auto bit = [](int x, int j) -> int {
return (x >> j) & 1;
};
auto solve = [&](auto&& self, int l, int r, int j) -> void {
if (l > r) return;
if (l == r) {
mate[l - L] = l;
return;
}
if (j < 0) {
for (int x = l; x <= r; x++) mate[x - L] = x;
return;
}
int mid = l;
int first = bit(l, j);
while (mid + 1 <= r && bit(mid + 1, j) == first) mid++;
if (mid == r) {
self(self, l, r, j - 1);
return;
}
int tl = mid + 1, tr = mid;
while (tl - 1 >= l && tr + 1 <= r) {
--tl;
++tr;
mate[tl - L] = tr;
mate[tr - L] = tl;
}
self(self, l, tl - 1, j - 1);
self(self, tr + 1, r, j - 1);
};
solve(solve, L, R, 29);
ll ans = 0;
for (int x = L; x <= R; x++) ans += (ll)(x | mate[x - L]);
cout << ans << '\n';
for (int x = L; x <= R; x++) cout << mate[x - L] << ' ';
cout << '\n';
}
}#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 L, R;
cin >> L >> R;
vector<int> mate(R - L + 1, -1);
auto bit = [](int x, int j) -> int {
return (x >> j) & 1;
};
auto solve = [&](auto&& self, int l, int r, int j) -> void {
if (l > r) return;
if (l == r) {
mate[l - L] = l;
return;
}
if (j < 0) {
for (int x = l; x <= r; x++) mate[x - L] = x;
return;
}
int mid = l;
int first = bit(l, j);
while (mid + 1 <= r && bit(mid + 1, j) == first) mid++;
if (mid == r) {
self(self, l, r, j - 1);
return;
}
int tl = mid + 1, tr = mid;
while (tl - 1 >= l && tr + 1 <= r) {
--tl;
++tr;
mate[tl - L] = tr;
mate[tr - L] = tl;
}
self(self, l, tl - 1, j - 1);
self(self, tr + 1, r, j - 1);
};
solve(solve, L, R, 29);
ll ans = 0;
for (int x = L; x <= R; x++) ans += (ll)(x | mate[x - L]);
cout << ans << '\n';
for (int x = L; x <= R; x++) cout << mate[x - L] << ' ';
cout << '\n';
}
}