Skip to content

Commit a11b985

Browse files
lrvideckisweb-flow
andauthored
xor basis walk (#193)
* first draft of walk for xor basis * [auto-verifier] verify commit 8c0af3f * changes * [auto-verifier] verify commit 796f68e * add assert to test it now * asdf * [auto-verifier] verify commit 504ae7d * fix test now * fix test * fix --------- Co-authored-by: GitHub <noreply@github.com>
1 parent d776b1c commit a11b985

6 files changed

Lines changed: 94 additions & 54 deletions

File tree

.verify-helper/timestamps.remote.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
"tests/library_checker_aizu_tests/handmade_tests/seg_tree_find.test.cpp": "2026-01-23 04:31:29 +0000",
9191
"tests/library_checker_aizu_tests/handmade_tests/seg_tree_find_small.test.cpp": "2026-01-23 04:31:29 +0000",
9292
"tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp": "2026-02-27 11:16:07 -0700",
93+
"tests/library_checker_aizu_tests/handmade_tests/xor_basis_walk.test.cpp": "2026-03-08 13:19:49 -0600",
9394
"tests/library_checker_aizu_tests/loops/chooses.test.cpp": "2025-02-10 14:50:36 -0700",
9495
"tests/library_checker_aizu_tests/loops/quotients.test.cpp": "2024-11-17 14:04:03 -0600",
9596
"tests/library_checker_aizu_tests/loops/submasks.test.cpp": "2025-02-10 14:50:36 -0700",
@@ -106,7 +107,6 @@
106107
"tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp": "2025-09-07 16:12:35 -0600",
107108
"tests/library_checker_aizu_tests/math/tetration.test.cpp": "2024-11-17 14:04:03 -0600",
108109
"tests/library_checker_aizu_tests/math/totient.test.cpp": "2024-11-17 14:04:03 -0600",
109-
"tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp": "2026-03-06 16:39:24 -0700",
110110
"tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_binary_tree.test.cpp": "2025-02-10 14:50:36 -0700",
111111
"tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_k_ary_tree.test.cpp": "2026-01-18 11:15:41 +0000",
112112
"tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2026-01-18 11:15:41 +0000",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bitset<B> walk(bitset<B>& k) {
2+
bitset<B> res;
3+
for (int i = B, j = npivot; i--;)
4+
if (basis[i][i] && res[i] ^ k[--j]) res ^= basis[i];
5+
return res;
6+
}

library/math/matrix_related/xor_basis_ordered.hpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
//! basis_ordered<int> b1;
66
//! basis_ordered<ll> b2;
77
//! basis_ordered<bitset<lg>> b3;
8-
//! b2.insert(x); // 0 <= x < (1LL<<lg)
8+
//! b2.insert(x); // 0 <= x < (1LL<<B)
99
//! @endcode
10-
//! @time O(lg)
11-
//! @space O(lg)
12-
const int lg = 60;
13-
template<class T> struct basis_ordered {
14-
int siz = 0;
15-
T b[lg]{};
16-
int shrink(T& v) {
17-
for (int i = lg - 1; i >= 0; i--)
18-
if (((v >> i) & T(1)) != T(0)) {
19-
if (b[i] == T(0)) return i;
20-
v ^= b[i];
10+
//! @time O(q * B^2/32)
11+
//! @space O(B^2/32)
12+
template<int B> struct xor_basis {
13+
bitset<B> basis[B];
14+
int npivot = 0, nfree = 0;
15+
int shrink(bitset<B>& v) {
16+
for (int i = B; i--;)
17+
if (v[i]) {
18+
if (!basis[i][i]) return i;
19+
v ^= basis[i];
2120
}
2221
return -1;
2322
}
24-
bool insert(T v) {
23+
bool insert(bitset<B>& v) {
2524
int i = shrink(v);
26-
return i >= 0 ? b[i] = v, ++siz : 0;
25+
return i >= 0 ? basis[i] = v, ++npivot : !++nfree;
2726
}
27+
#include "walk.hpp"
2828
};

tests/.config/.cppcheck_suppression_list

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,3 @@ unusedFunction:../kactl/stress-tests/utilities/genTree.h:49
6363
containerOutOfBounds:../library/data_structures_[l,r)/uncommon/permutation_tree.hpp:85
6464
ctuOneDefinitionRuleViolation:../library/data_structures_[l,r)/bit.hpp:5
6565
ctuOneDefinitionRuleViolation:../library/data_structures_[l,r)/lazy_seg_tree.hpp:4
66-
shiftTooManyBits:../library/math/matrix_related/xor_basis_ordered.hpp:18
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#define PROBLEM \
2+
"https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A"
3+
#include "../template.hpp"
4+
#include "../../../library/contest/random.hpp"
5+
#include "../../../library/math/matrix_related/xor_basis_ordered.hpp"
6+
const int B = 18;
7+
vector<bitset<B>> get_all(const vector<bitset<B>>& basis) {
8+
int n = ssize(basis);
9+
vector<bitset<B>> span;
10+
for (int mask = 0; mask < (1 << n); mask++) {
11+
bitset<B> curr_xor;
12+
assert(curr_xor.none());
13+
for (int bit = 0; bit < n; bit++)
14+
if ((mask >> bit) & 1) curr_xor ^= basis[bit];
15+
span.push_back(curr_xor);
16+
}
17+
ranges::sort(span, {}, [&](const bitset<B>& x) -> long {
18+
return x.to_ulong();
19+
});
20+
return span;
21+
}
22+
int main() {
23+
cin.tie(0)->sync_with_stdio(0);
24+
for (int num_tests = 0; num_tests < 1000; num_tests++) {
25+
xor_basis<B> b;
26+
int n = rnd(1, 18);
27+
vector<bitset<B>> naive_basis;
28+
for (int i = 0; i < n; i++) {
29+
bitset<B> val = rnd(0, (1 << n) - 1);
30+
if (b.insert(val)) naive_basis.push_back(val);
31+
assert(b.npivot + b.nfree == i + 1);
32+
}
33+
assert(ssize(naive_basis) == b.npivot);
34+
vector<bitset<B>> fast_basis;
35+
for (int i = 0; i < B; i++)
36+
if (b.basis[i][i]) fast_basis.push_back(b.basis[i]);
37+
vector<bitset<B>> naive_span = get_all(naive_basis);
38+
vector<bitset<B>> fast_span = get_all(fast_basis);
39+
assert(naive_span == fast_span);
40+
for (int i = 0; i < ssize(naive_span); i++) {
41+
bitset<B> k = i;
42+
assert(naive_span[i] == b.walk(k));
43+
}
44+
}
45+
cout << "Hello World\n";
46+
}

tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,16 @@ void check_condition_unordered(const basis& b) {
1414
or_bits |= b.b[i];
1515
}
1616
}
17-
void check_condition_ordered(
18-
const basis_ordered<ll>& basis3,
19-
const basis_ordered<bitset<lg>>& basis4) {
20-
ll or_bits3 = 0;
21-
bitset<lg> or_bits4 = 0;
22-
for (int i = 0; i < lg; i++) {
23-
assert(basis3.b[i] == 0 ||
24-
bit_floor(1ULL * basis3.b[i]) == (1ULL << i));
25-
assert(
26-
(bit_floor(uint64_t(basis3.b[i])) & or_bits3) == 0);
27-
assert((bit_floor(uint64_t(basis4.b[i].to_ullong())) &
28-
or_bits4.to_ullong()) == 0);
29-
or_bits3 |= basis3.b[i];
30-
or_bits4 |= basis4.b[i];
17+
const int B = 30;
18+
void check_condition_ordered(const xor_basis<B>& basis2) {
19+
bitset<B> or_bits2;
20+
for (int i = 0; i < B; i++) {
21+
assert(basis2.basis[i].none() ||
22+
bit_floor(basis2.basis[i].to_ulong()) ==
23+
(1ULL << i));
24+
assert((bit_floor(basis2.basis[i].to_ulong()) &
25+
or_bits2.to_ulong()) == 0);
26+
or_bits2 |= basis2.basis[i];
3127
}
3228
}
3329
int main() {
@@ -38,43 +34,36 @@ int main() {
3834
int n;
3935
cin >> n;
4036
basis basis1;
41-
basis_ordered<int> basis2; // to check that it compiles
42-
assert(
43-
sz(basis2.b) == lg); // remove unused var warning
44-
basis_ordered<ll> basis3;
45-
basis_ordered<bitset<lg>> basis4;
37+
xor_basis<B> basis2;
38+
for (int i = 0; i < B; i++)
39+
assert(basis2.basis[i].none());
4640
for (int i = 0; i < n; i++) {
4741
int val;
4842
cin >> val;
43+
bitset<B> v = val;
4944
assert(basis1.insert(val));
5045
assert(!basis1.insert(val));
51-
assert(basis3.insert(val));
52-
assert(!basis3.insert(val));
53-
assert(basis4.insert(val));
54-
assert(!basis4.insert(val));
46+
assert(basis2.insert(v));
47+
assert(!basis2.insert(v));
5548
}
5649
check_condition_unordered(basis1);
57-
check_condition_ordered(basis3, basis4);
50+
check_condition_ordered(basis2);
5851
int m;
5952
cin >> m;
60-
basis basis5;
61-
basis_ordered<int> basis6;
62-
assert(sz(basis6.b) == lg);
63-
basis_ordered<ll> basis7;
64-
basis_ordered<bitset<lg>> basis8;
53+
basis basis3;
54+
xor_basis<B> basis4;
6555
for (int j = 0; j < m; j++) {
6656
int val;
6757
cin >> val;
68-
assert(basis5.insert(val));
69-
assert(!basis5.insert(val));
70-
assert(basis7.insert(val));
71-
assert(!basis7.insert(val));
72-
assert(basis8.insert(val));
73-
assert(!basis8.insert(val));
58+
bitset<B> v = val;
59+
assert(basis3.insert(val));
60+
assert(!basis3.insert(val));
61+
assert(basis4.insert(v));
62+
assert(!basis4.insert(v));
7463
}
75-
check_condition_unordered(basis5);
76-
check_condition_ordered(basis7, basis8);
77-
basis inter = intersection(basis1, basis5);
64+
check_condition_unordered(basis3);
65+
check_condition_ordered(basis4);
66+
basis inter = intersection(basis1, basis3);
7867
check_condition_unordered(inter);
7968
cout << sz(inter.b) << " ";
8069
for (int val : inter.b) cout << val << " ";

0 commit comments

Comments
 (0)