library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:heavy_check_mark: alg/monoid/merge_vector_space.hpp

Depends on

Verified with

Code

#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;
};
Back to top page