diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index c50e6702..4e850ec5 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -90,6 +90,7 @@ "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find.test.cpp": "2026-01-23 04:31:29 +0000", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_find_small.test.cpp": "2026-01-23 04:31:29 +0000", "tests/library_checker_aizu_tests/handmade_tests/seg_tree_midpoint.test.cpp": "2026-02-27 11:16:07 -0700", +"tests/library_checker_aizu_tests/handmade_tests/xor_basis_walk.test.cpp": "2026-03-08 13:19:49 -0600", "tests/library_checker_aizu_tests/loops/chooses.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/loops/quotients.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/loops/submasks.test.cpp": "2025-02-10 14:50:36 -0700", @@ -106,7 +107,6 @@ "tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp": "2025-09-07 16:12:35 -0600", "tests/library_checker_aizu_tests/math/tetration.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/math/totient.test.cpp": "2024-11-17 14:04:03 -0600", -"tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp": "2026-03-06 16:39:24 -0700", "tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_binary_tree.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/monotonic_stack_related/cartesian_k_ary_tree.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/monotonic_stack_related/count_rectangles.test.cpp": "2026-01-18 11:15:41 +0000", diff --git a/library/math/matrix_related/walk.hpp b/library/math/matrix_related/walk.hpp new file mode 100644 index 00000000..a28bbf8e --- /dev/null +++ b/library/math/matrix_related/walk.hpp @@ -0,0 +1,6 @@ +bitset walk(bitset& k) { + bitset res; + for (int i = B, j = npivot; i--;) + if (basis[i][i] && res[i] ^ k[--j]) res ^= basis[i]; + return res; +} diff --git a/library/math/matrix_related/xor_basis_ordered.hpp b/library/math/matrix_related/xor_basis_ordered.hpp index 7cadd72d..b3c01848 100644 --- a/library/math/matrix_related/xor_basis_ordered.hpp +++ b/library/math/matrix_related/xor_basis_ordered.hpp @@ -5,24 +5,24 @@ //! basis_ordered b1; //! basis_ordered b2; //! basis_ordered> b3; -//! b2.insert(x); // 0 <= x < (1LL< struct basis_ordered { - int siz = 0; - T b[lg]{}; - int shrink(T& v) { - for (int i = lg - 1; i >= 0; i--) - if (((v >> i) & T(1)) != T(0)) { - if (b[i] == T(0)) return i; - v ^= b[i]; +//! @time O(q * B^2/32) +//! @space O(B^2/32) +template struct xor_basis { + bitset basis[B]; + int npivot = 0, nfree = 0; + int shrink(bitset& v) { + for (int i = B; i--;) + if (v[i]) { + if (!basis[i][i]) return i; + v ^= basis[i]; } return -1; } - bool insert(T v) { + bool insert(bitset& v) { int i = shrink(v); - return i >= 0 ? b[i] = v, ++siz : 0; + return i >= 0 ? basis[i] = v, ++npivot : !++nfree; } +#include "walk.hpp" }; diff --git a/tests/.config/.cppcheck_suppression_list b/tests/.config/.cppcheck_suppression_list index d6ad7f70..aa381399 100644 --- a/tests/.config/.cppcheck_suppression_list +++ b/tests/.config/.cppcheck_suppression_list @@ -63,4 +63,3 @@ unusedFunction:../kactl/stress-tests/utilities/genTree.h:49 containerOutOfBounds:../library/data_structures_[l,r)/uncommon/permutation_tree.hpp:85 ctuOneDefinitionRuleViolation:../library/data_structures_[l,r)/bit.hpp:5 ctuOneDefinitionRuleViolation:../library/data_structures_[l,r)/lazy_seg_tree.hpp:4 -shiftTooManyBits:../library/math/matrix_related/xor_basis_ordered.hpp:18 diff --git a/tests/library_checker_aizu_tests/handmade_tests/xor_basis_walk.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/xor_basis_walk.test.cpp new file mode 100644 index 00000000..8c5ce1e1 --- /dev/null +++ b/tests/library_checker_aizu_tests/handmade_tests/xor_basis_walk.test.cpp @@ -0,0 +1,46 @@ +#define PROBLEM \ + "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" +#include "../template.hpp" +#include "../../../library/contest/random.hpp" +#include "../../../library/math/matrix_related/xor_basis_ordered.hpp" +const int B = 18; +vector> get_all(const vector>& basis) { + int n = ssize(basis); + vector> span; + for (int mask = 0; mask < (1 << n); mask++) { + bitset curr_xor; + assert(curr_xor.none()); + for (int bit = 0; bit < n; bit++) + if ((mask >> bit) & 1) curr_xor ^= basis[bit]; + span.push_back(curr_xor); + } + ranges::sort(span, {}, [&](const bitset& x) -> long { + return x.to_ulong(); + }); + return span; +} +int main() { + cin.tie(0)->sync_with_stdio(0); + for (int num_tests = 0; num_tests < 1000; num_tests++) { + xor_basis b; + int n = rnd(1, 18); + vector> naive_basis; + for (int i = 0; i < n; i++) { + bitset val = rnd(0, (1 << n) - 1); + if (b.insert(val)) naive_basis.push_back(val); + assert(b.npivot + b.nfree == i + 1); + } + assert(ssize(naive_basis) == b.npivot); + vector> fast_basis; + for (int i = 0; i < B; i++) + if (b.basis[i][i]) fast_basis.push_back(b.basis[i]); + vector> naive_span = get_all(naive_basis); + vector> fast_span = get_all(fast_basis); + assert(naive_span == fast_span); + for (int i = 0; i < ssize(naive_span); i++) { + bitset k = i; + assert(naive_span[i] == b.walk(k)); + } + } + cout << "Hello World\n"; +} diff --git a/tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp b/tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp index b898fd62..f4145d77 100644 --- a/tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp +++ b/tests/library_checker_aizu_tests/math/xor_basis_intersection.test.cpp @@ -14,20 +14,16 @@ void check_condition_unordered(const basis& b) { or_bits |= b.b[i]; } } -void check_condition_ordered( - const basis_ordered& basis3, - const basis_ordered>& basis4) { - ll or_bits3 = 0; - bitset or_bits4 = 0; - for (int i = 0; i < lg; i++) { - assert(basis3.b[i] == 0 || - bit_floor(1ULL * basis3.b[i]) == (1ULL << i)); - assert( - (bit_floor(uint64_t(basis3.b[i])) & or_bits3) == 0); - assert((bit_floor(uint64_t(basis4.b[i].to_ullong())) & - or_bits4.to_ullong()) == 0); - or_bits3 |= basis3.b[i]; - or_bits4 |= basis4.b[i]; +const int B = 30; +void check_condition_ordered(const xor_basis& basis2) { + bitset or_bits2; + for (int i = 0; i < B; i++) { + assert(basis2.basis[i].none() || + bit_floor(basis2.basis[i].to_ulong()) == + (1ULL << i)); + assert((bit_floor(basis2.basis[i].to_ulong()) & + or_bits2.to_ulong()) == 0); + or_bits2 |= basis2.basis[i]; } } int main() { @@ -38,43 +34,36 @@ int main() { int n; cin >> n; basis basis1; - basis_ordered basis2; // to check that it compiles - assert( - sz(basis2.b) == lg); // remove unused var warning - basis_ordered basis3; - basis_ordered> basis4; + xor_basis basis2; + for (int i = 0; i < B; i++) + assert(basis2.basis[i].none()); for (int i = 0; i < n; i++) { int val; cin >> val; + bitset v = val; assert(basis1.insert(val)); assert(!basis1.insert(val)); - assert(basis3.insert(val)); - assert(!basis3.insert(val)); - assert(basis4.insert(val)); - assert(!basis4.insert(val)); + assert(basis2.insert(v)); + assert(!basis2.insert(v)); } check_condition_unordered(basis1); - check_condition_ordered(basis3, basis4); + check_condition_ordered(basis2); int m; cin >> m; - basis basis5; - basis_ordered basis6; - assert(sz(basis6.b) == lg); - basis_ordered basis7; - basis_ordered> basis8; + basis basis3; + xor_basis basis4; for (int j = 0; j < m; j++) { int val; cin >> val; - assert(basis5.insert(val)); - assert(!basis5.insert(val)); - assert(basis7.insert(val)); - assert(!basis7.insert(val)); - assert(basis8.insert(val)); - assert(!basis8.insert(val)); + bitset v = val; + assert(basis3.insert(val)); + assert(!basis3.insert(val)); + assert(basis4.insert(v)); + assert(!basis4.insert(v)); } - check_condition_unordered(basis5); - check_condition_ordered(basis7, basis8); - basis inter = intersection(basis1, basis5); + check_condition_unordered(basis3); + check_condition_ordered(basis4); + basis inter = intersection(basis1, basis3); check_condition_unordered(inter); cout << sz(inter.b) << " "; for (int val : inter.b) cout << val << " ";