PROBLEM LINK:
Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4
Author: munch_01
Tester: raysh_07
Editorialist: iceknight1093
DIFFICULTY:
TBD
PREREQUISITES:
None
PROBLEM:
You’re given an integer X.
Find any pair (A, B) such that:
- 0 \leq A \leq B \leq X
- A\oplus B = X
- (B-A) is as small as possible across all pairs satisfying the first two conditions.
EXPLANATION:
Given that we’re dealing with bitwise XOR, it’s useful to look at the binary representation of X.
So, let
where x_1 \lt x_2 \lt\ldots\lt x_k are the set bits in the binary representation of X.
Now, for A\oplus B = X to hold:
- Each x_i should be set in exactly one of A and B, not both.
- Each bit that’s not one of the x_i should be set in either both A and B, or neither of them.
Further, the condition 0 \leq A \leq B \leq X means that:
- Any bit higher than x_k isn’t allowed to be set in either A or B (otherwise they’d exceed X).
- Bit x_k must be set in B, to ensure A \leq B.
Now that x_k is decided, we need to fix the other k-1 of them.
Let’s just give them all to A, making it as large as possible - after all, our aim is to minimize B-A.
That is, we have B = 2^{x_k} and A = 2^{x_1} + 2^{x_2} + \ldots + 2^{x_{k-1}}.
This is a valid solution, because:
- As noted earlier, any bit which isn’t one of the x_i should be set in both A and B, or neither of them.
As of now, they’re all unset in both: and setting them won’t change the difference since both A and B increase by the same value. - Moving one of the x_i from A to B is clearly only going to make the difference larger, given that A decreases while B increases.
TIME COMPLEXITY:
\mathcal{O}(\log X) per testcase.
CODE:
Tester's code (C++)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)1e18
#define f first
#define s second
mt19937_64 RNG(chrono::steady_clock::now().time_since_epoch().count());
struct input_checker {
string buffer;
int pos;
const string all = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const string number = "0123456789";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string lower = "abcdefghijklmnopqrstuvwxyz";
input_checker() {
pos = 0;
while (true) {
int c = cin.get();
if (c == -1) {
break;
}
buffer.push_back((char) c);
}
}
int nextDelimiter() {
int now = pos;
while (now < (int) buffer.size() && !isspace(buffer[now])) {
now++;
}
return now;
}
string readOne() {
assert(pos < (int) buffer.size());
int nxt = nextDelimiter();
string res;
while (pos < nxt) {
res += buffer[pos];
pos++;
}
return res;
}
string readString(int minl, int maxl, const string &pattern = "") {
assert(minl <= maxl);
string res = readOne();
assert(minl <= (int) res.size());
assert((int) res.size() <= maxl);
for (int i = 0; i < (int) res.size(); i++) {
assert(pattern.empty() || pattern.find(res[i]) != string::npos);
}
return res;
}
int readInt(int minv, int maxv) {
assert(minv <= maxv);
int res = stoi(readOne());
assert(minv <= res);
assert(res <= maxv);
return res;
}
long long readLong(long long minv, long long maxv) {
assert(minv <= maxv);
long long res = stoll(readOne());
assert(minv <= res);
assert(res <= maxv);
return res;
}
auto readInts(int n, int minv, int maxv) {
assert(n >= 0);
vector<int> v(n);
for (int i = 0; i < n; ++i) {
v[i] = readInt(minv, maxv);
if (i+1 < n) readSpace();
}
return v;
}
auto readLongs(int n, long long minv, long long maxv) {
assert(n >= 0);
vector<long long> v(n);
for (int i = 0; i < n; ++i) {
v[i] = readLong(minv, maxv);
if (i+1 < n) readSpace();
}
return v;
}
void readSpace() {
assert((int) buffer.size() > pos);
assert(buffer[pos] == ' ');
pos++;
}
void readEoln() {
assert((int) buffer.size() > pos);
assert(buffer[pos] == '\n');
pos++;
}
void readEof() {
assert((int) buffer.size() == pos);
}
};
input_checker inp;
const int T = 1e5;
const int N = 1e9;
void Solve()
{
int n = inp.readInt(1, N); inp.readEoln();
int a = 0, b = 0;
int cnt = 0;
for (int i = 31; i >= 0; i--) if (n >> i & 1){
cnt++;
if (cnt == 1) a += 1 << i;
else b += 1 << i;
}
swap(a, b);
cout << a << " " << b << "\n";
}
int32_t main()
{
auto begin = std::chrono::high_resolution_clock::now();
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
t = inp.readInt(1, T);
inp.readEoln();
for(int i = 1; i <= t; i++)
{
//cout << "Case #" << i << ": ";
Solve();
}
inp.readEof();
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
cerr << "Time measured: " << elapsed.count() * 1e-9 << " seconds.\n";
return 0;
}
Editorialist's code (Python)
for _ in range(int(input())):
x = int(input())
a, b = 0, 0
for i in range(30):
if x & 2**i:
a += b
b = 2**i
print(a, b)