XORRY2 - Editorial

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 the number of pairs (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:

It is recommended to read the editorial of XORRY1 first, since this will continue from there.

As before, let x_1 \lt x_2 \lt\ldots\lt x_k be the set bits in the binary representation of X.
We observed that:

  • One solution is obtained by setting B = 2^{x_k} and A = 2^{x_1} + 2^{x_2} + \ldots + 2^{x_{k-1}}.
  • Moving any of these x_i from A over to B will increase the difference, and so isn’t optimal.
  • For all bits that aren’t one of the x_i, they must be set in either both A and B, or they must not be.
    However, whether they are set or not doesn’t affect the difference (B-A) at all.

So, each bit other than the x_i has a choice: it can be either set or unset.
However, we need to ensure that A and B don’t exceed X while doing this.
To that end, observe that:

  • Setting any bit higher than x_k will cause both A and B to exceed X, so we can’t do this.
  • Setting any bit between x_{k-1} and x_k will cause B to exceed X so we can’t do this either.
  • Setting any bit lower than x_{k-1} won’t cause any issues, since even if all of them were set, B's value is bounded above by 2^{x_k} + 2^{x_{k-1}} which can’t exceed X.

This means, if there are m bits below x_{k-1} that are ‘free’, the answer is simply 2^m — for each of them, we can independently choose whether to set it or not.
Finding the number of such bits is easy in \mathcal{O}(\log X) since you can just iterate each bit to check.

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 ans = 1;
    int cnt = 0;
    for (int i = 31; i >= 0; i--){
        if (n >> i & 1){
            cnt++;
        } else {
            if (cnt >= 2) ans *= 2;
        }
    }

    cout << ans << "\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
    ans = 1
    for i in range(30):
        if 2**i <= a and (x & 2**i == 0): ans *= 2
    print(ans)