This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub maspypy/library
#include "alg/monoid/merge_vector_space.hpp"
#include "linalg/xor/vector_space.hpp" template <typename UINT> struct Merge_Vector_Space { using value_type = Vector_Space<UINT>; using X = value_type; static X op(X x, X y) { return Vector_Space<UINT>::merge(x, y); } static constexpr X unit() { return {}; } static constexpr bool commute = 1; };
#line 2 "linalg/xor/transpose.hpp" // n x m 行列の transpose。O((n+m)log(n+m)) 時間。 // https://github.com/dsnet/matrix-transpose template <typename UINT> vc<UINT> transpose(int n, int m, vc<UINT>& A, bool keep_A = 1) { assert(max(n, m) <= numeric_limits<UINT>::digits); assert(len(A) == n); vc<UINT> tmp; if (keep_A) tmp = A; int LOG = 0; while ((1 << LOG) < max(n, m)) ++LOG; A.resize(1 << LOG); int width = 1 << LOG; UINT mask = 1; FOR(i, LOG) mask = mask | (mask << (1 << i)); FOR(t, LOG) { width >>= 1; mask = mask ^ (mask >> width); FOR(i, 1 << t) { FOR(j, width) { UINT* x = &A[width * (2 * i + 0) + j]; UINT* y = &A[width * (2 * i + 1) + j]; *x = ((*y << width) & mask) ^ *x; *y = ((*x & mask) >> width) ^ *y; *x = ((*y << width) & mask) ^ *x; } } } A.resize(m); if (!keep_A) return A; swap(A, tmp); return tmp; } #line 2 "linalg/xor/vector_space.hpp" template <typename UINT> struct Vector_Space { #define SP Vector_Space vc<UINT> dat; Vector_Space() {} Vector_Space(vc<UINT> dat, bool is_reduced = false) : dat(dat) { if (!is_reduced) reduce(); } int size() { return dat.size(); } int dim() { return dat.size(); } bool add_element(UINT v) { for (auto&& e: dat) { if (e == 0 || v == 0) break; chmin(v, v ^ e); } if (v) { dat.eb(v); return true; } return false; } bool contain(UINT v) { for (auto&& w: dat) { if (v == 0) break; chmin(v, v ^ w); } return v == 0; } UINT get_max(UINT xor_val = 0) { UINT res = xor_val; for (auto&& x: dat) chmax(res, res ^ x); return res; } UINT get_min(UINT xor_val) { UINT res = xor_val; for (auto&& x: dat) chmin(res, res ^ x); return res; } static SP merge(SP x, SP y) { if (len(x) < len(y)) swap(x, y); for (auto v: y.dat) { x.add_element(v); } return x; } static SP intersection(SP& x, SP& y) { // とりあえず static_assert(is_same_v<UINT, u32>); vc<u64> xx; for (auto& v: x.dat) xx.eb(v | static_cast<u64>(v) << 32); Vector_Space<u64> z(xx, true); for (auto& v: y.dat) z.add_element(static_cast<u64>(v) << 32); vc<u32> xy; for (auto& v: z.dat) { if (v <= u32(-1)) xy.eb(v); } return SP(xy, true); } SP orthogonal_space(int max_dim) { normalize(); int m = max_dim; // pivot[k] == k となるように行の順番を変える vc<u64> tmp(m); FOR(i, len(dat)) tmp[topbit(dat[i])] = dat[i]; tmp = transpose(m, m, tmp, 0); SP res; FOR(j, m) { if (tmp[j] >> j & 1) continue; res.add_element(tmp[j] | UINT(1) << j); } return res; } void normalize(bool dec = true) { int n = len(dat); // 三角化 FOR(j, n) FOR(i, j) chmin(dat[i], dat[i] ^ dat[j]); sort(all(dat)); if (dec) reverse(all(dat)); } private: void reduce() { SP y; for (auto&& e: dat) y.add_element(e); (*this) = y; } #undef SP }; #line 2 "alg/monoid/merge_vector_space.hpp" template <typename UINT> struct Merge_Vector_Space { using value_type = Vector_Space<UINT>; using X = value_type; static X op(X x, X y) { return Vector_Space<UINT>::merge(x, y); } static constexpr X unit() { return {}; } static constexpr bool commute = 1; };