Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Elementary Algorithms / Bit Manipulation

An XOR basis (also called a linear basis over the field GF(2)) is the analog of a vector space basis for integers under the bitwise XOR operation. Each integer is treated as a vector of bits, where XOR plays the role of vector addition. Inserting a set of integers one at a time and keeping only those that are linearly independent yields a basis whose XOR-combinations (subset XORs) span exactly the same set of values as the original integers. From a basis of size $r$, exactly $2^r$ distinct values are reachable, and queries such as the maximum attainable XOR become a simple greedy scan.

The basis is kept in row-echelon form: the $i$-th basis element is either $0$ or a value whose highest set bit is bit $i$, and no two basis elements share the same highest bit. Reducing a value means XORing it against the basis elements from the highest bit down, eliminating each set bit that a basis element covers.

  • XorBasis() constructs an empty basis over Mask, which is uint64_t by default.
  • insert(x) adds x to the basis, returning true if x was linearly independent of the current basis (increasing its size), or false if x was already representable as a subset XOR.
  • contains(x) returns whether x is representable as the XOR of some subset of the inserted values, i.e. whether it reduces to $0$ against the basis.
  • max_xor(base = 0) returns the maximum value of base XORed with some subset XOR of the basis. With the default base of $0$, this is the maximum subset XOR.
  • size() returns the number of elements in the basis (its rank).

Implementation

#include <array>
#include <climits>
#include <cstdint>

using Mask = uint64_t;
const int MASK_BITS = sizeof(Mask) * CHAR_BIT;

class XorBasis {
  std::array<Mask, MASK_BITS> basis{};  // basis[i] != 0 has its highest set bit at bit i.
  int basis_size = 0;

 public:
  bool insert(Mask x) {
    for (int i = MASK_BITS - 1; i >= 0; i--) {
      if (!((x >> i) & 1)) {
        continue;
      }
      if (basis[i] == 0) {
        basis[i] = x;
        basis_size++;
        return true;
      }
      x ^= basis[i];
    }
    return false;
  }

  bool contains(Mask x) const {
    for (int i = MASK_BITS - 1; i >= 0; i--) {
      if (((x >> i) & 1) && basis[i] != 0) {
        x ^= basis[i];
      }
    }
    return x == 0;
  }

  Mask max_xor(Mask base = 0) const {
    for (int i = MASK_BITS - 1; i >= 0; i--) {
      if ((base ^ basis[i]) > base) {
        base ^= basis[i];
      }
    }
    return base;
  }

  int size() const { return basis_size; }
};

Example Usage

#include <cassert>

int main() {
  XorBasis b;
  assert(b.insert(1));   // 001
  assert(b.insert(2));   // 010
  assert(!b.insert(3));  // 011 = 1 ^ 2, already representable.
  assert(b.size() == 2);

  assert(b.contains(3));
  assert(b.contains(0));
  assert(!b.contains(4));

  assert(b.max_xor() == 3);   // Best subset XOR over {0, 1, 2, 3}.
  assert(b.max_xor(4) == 7);  // 4 ^ 3.
  return 0;
}