G - Partial Xor Enumeration Editorial by en_translator
This article uses many terms of linear algebra. Also, the 1-based indexing in the problem statement is translated to the 0-based one.
An integer between \(0\) (inclusive) and \(2^{60}\) can be considered as an element of a vector space \({\mathbb{F}_2}^{60}\), and the exclusive logical sum \(\operatorname{xor}\) as the addition on the space.
Noting that \(\mathbb{F}_2=\lbrace0,1\rbrace\), the \(\operatorname{xor}\) of one or more positive integers chosen from \(A=(A _ 0,\ldots,A _ {N-1})\) can be represented by \(\displaystyle\sum _ {i=0} ^ {N-1}c _ i\bm{a} _ i\), a linear combination of the sequence \((\bm{a} _ i) _ {0\leq i\lt N}\) of vectors that corresponds to the elements of \(A\). Conversely, a vector that is represented by such a linear combination corresponds to the \(\operatorname{xor}\) of one or more vectors chosen from the original sequence.
Therefore, once we obtain the basis \((\bm{e} _ i) _ {0\leq i\lt x}\) of the subspace of \({\mathbb{F}_2}^{60}\) spanned by \((\bm{a} _ i) _ {0\leq i\lt N}\), we can obtain the expression that corresponds one-by-one to the \(\operatorname{xor}\).
Especially, one can take a basis that looks like:
\[ \left\lparen\begin{matrix}\bm e _ 0\\\vdots\\\bm e _ i\\\vdots\\\bm e _ {x-1}\end{matrix}\right\rparen=\left\lparen\ \begin{matrix}0&\cdots&0&0&\cdots&0&0&0&\cdots&0&1&\ast&\cdots&\ast\\\vdots&\ddots&\vdots&\vdots&\ddots&\vdots&\vdots&\vdots&\ddots&\vdots&\vdots&\vdots&\ddots&\vdots\\0&\cdots&0&0&\cdots&0&1&\ast&\cdots&\ast&0&\ast&\cdots&\ast\\\vdots&\ddots&\vdots&\vdots&\ddots&\vdots&\vdots&\vdots&\ddots&\vdots&\vdots&\vdots&\ddots&\vdots\\0&\cdots&1&\ast&\cdots&\ast&0&\ast&\cdots&\ast&0&\ast&\cdots&\ast\end{matrix}\ \right\rparen \]
In terms of integers, the basis satisfies the following two conditions:
- \(e _ 0\lt e _ 1\lt\cdots\lt e _ {x-1}\);
- If \(i\neq j\), then the \(b\)-th significant bit of \(e _ j\) is \(0\), where the \(\operatorname{msb}\) (most significant bit) of \(e _ i\) is the \(b\operatorname{bit}\)-th one.
Such a basis can be constructed by tweaking the algorithm of constructing noshi’s basis.
Once we obtained such a basis, the vector \(\bm s _ i\) that corresponds to the \(i\)-th smallest value \(s _ i\) of total \(\operatorname{xor}\) can be represented as \(\displaystyle\bm s _ i=\sum_{b=0}^{x-1}c _ i\bm e _ i\), where \(c_i\) is the binary notation of \(i\), that is, \(\displaystyle i=\sum _ {b=0} ^ {x-1}c _ i2 ^ i\ (c _ i=0,1)\).
Therefore, given some \(X\), the value of \(s _ X\) can be obtained in an \(O(x)\) time, where \(x\) is the size of the basis.
Given a length-\(N\) sequence of positive integers (that fit in the word size), finding the basis can be found in an \(O(Nx)\) time; together with sorting the basis in ascending order, the problem can be solved in a total of \(O((N+(R-L))x)\) time. Since \(x\) is the size of the basis of a subspace of \({\mathbb{F}_2}^{60}\), we have \(0\leq x\leq 60\), so it is fast enough.
One can modify the form of the basis to solve it in a total of \(O(Nx+(R-L))\) time.
The following is a sample code.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
using namespace std;
int N;
cin >> N;
unsigned long L, R;
cin >> L >> R;
--L;
--R;
// Construct the basis
vector<unsigned long> basis;
for (int i = 0; i < N; ++i) {
unsigned long A;
cin >> A;
for (auto b : basis)
if ((A ^ b) < A)
A ^= b;
for (auto &&b : basis)
if ((A ^ b) < b)
b ^= A;
if (A)
basis.emplace_back(A);
}
// sort in ascending order
sort(begin(basis), end(basis));
// Obtain the L-th value
unsigned long ans{};
for (int i = 0; i < 60; ++i)
if (L >> i & 1)
ans ^= basis[i];
for (int i = 1; i < size(basis); ++i)
basis[i] ^= basis[i - 1];
// Print the L-th through R-th values
cout << ans;
for (unsigned long x{L}; x < R; ++x) {
ans ^= basis[__builtin_popcountl(x ^ (x + 1)) - 1]; // Update the difference
cout << " " << ans;
}
cout << endl;
return 0;
}
posted:
last update: