Nyaan's Library

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

View on GitHub

:heavy_check_mark: 掃き出し法
(math/sweep.hpp)

Verified with

Code

#pragma once

#include <array>
#include <vector>
using namespace std;

// MAX bit
template <typename Int, int MAX>
struct Basis {
  array<Int, MAX> v;

  Basis() : _size(0) { fill(begin(v), end(v), Int{0}); }
  Basis(const vector<Int>& a) : _size(0) {
    fill(begin(v), end(v), Int{0});
    for (auto& x : a) add(x);
  }
  const Int operator[](int i) const { return v[i]; }

  // 追加成功かどうかを返す
  bool add(Int x) {
    int t = _msb(x);
    assert(t < MAX);
    while (t != -1 && v[t]) t = _msb(x ^= v[t]);
    return t == -1 ? false : (v[t] = x, _size++, true);
  }

  // rhs との和を求める
  void merge(const Basis& rhs) {
    for (int _t = MAX - 1; _t >= 0; _t--) {
      if (rhs.v[_t] == Int{0}) continue;
      int t = _t;
      Int x = rhs.v[t];
      while (t != -1 && v[t]) t = _msb(x ^= v[t]);
      if (x) v[t] = x, _size++;
    }
  }

  // 正規化された基底を得る (O(MAX^2))
  vector<Int> get_basis() {
    normalize();
    vector<Int> res;
    for (int t = 0; t < MAX; t++) {
      if (v[t]) res.push_back(v[t]);
    }
    reverse(begin(res), end(res));
    return res;
  }

  // x を作れるか? TODO:verify
  bool test(Int x) {
    if (x == 0) return true;
    int t = _msb(x);
    if (t >= MAX) return false;
    while (t != -1 && v[t]) t = _msb(x ^= v[t]);
    return x == 0;
  }

  // 作れる x の最大値 TODO:verify
  Int get_max() const {
    Int res = 0;
    for (int t = MAX - 1; t >= 0; t--) res = max(res, res ^ v[t]);
    return res;
  }

  // 行列を標準化する
  void normalize() {
    for (int t = MAX - 1; t >= 0; t--) {
      if (v[t]) {
        for (int u = MAX - 1; u > t; u--) v[u] = min(v[u], v[u] ^ v[t]);
      }
    }
  }

  vector<Int> orthogonal_complement(int N = MAX) {
    normalize();
    vector<int> b;
    for (int t = N - 1; t >= 0; t--) {
      if (v[t]) b.push_back(t);
    }
    int rank = b.size();
    for (int t = N - 1; t >= 0; t--) {
      if (!v[t]) b.push_back(t);
    }
    vector<Int> res(N - rank);
    for (int i = rank; i < N; i++) {
      for (int j = 0; j < N; j++) {
        if (j < rank ? ((v[b[j]] >> b[i]) & 1) : i == j) {
          res[i - rank] |= Int{1} << b[j];
        }
      }
    }
    return res;
  }

  int size() const { return _size; }

  friend ostream& operator<<(ostream& os, const Basis<Int, MAX>& b) {
    os << "{ ";
    for (int i = 0; i < MAX; i++) {
      if (b.v[i]) os << b.v[i] << ", ";
    }
    return os << "}";
  }

 private:
  int _size;
  int _msb(Int x) { return x ? 63 - __builtin_clzll(x) : -1; }
};

/*
 * @brief 掃き出し法
 */
#line 2 "math/sweep.hpp"

#include <array>
#include <vector>
using namespace std;

// MAX bit
template <typename Int, int MAX>
struct Basis {
  array<Int, MAX> v;

  Basis() : _size(0) { fill(begin(v), end(v), Int{0}); }
  Basis(const vector<Int>& a) : _size(0) {
    fill(begin(v), end(v), Int{0});
    for (auto& x : a) add(x);
  }
  const Int operator[](int i) const { return v[i]; }

  // 追加成功かどうかを返す
  bool add(Int x) {
    int t = _msb(x);
    assert(t < MAX);
    while (t != -1 && v[t]) t = _msb(x ^= v[t]);
    return t == -1 ? false : (v[t] = x, _size++, true);
  }

  // rhs との和を求める
  void merge(const Basis& rhs) {
    for (int _t = MAX - 1; _t >= 0; _t--) {
      if (rhs.v[_t] == Int{0}) continue;
      int t = _t;
      Int x = rhs.v[t];
      while (t != -1 && v[t]) t = _msb(x ^= v[t]);
      if (x) v[t] = x, _size++;
    }
  }

  // 正規化された基底を得る (O(MAX^2))
  vector<Int> get_basis() {
    normalize();
    vector<Int> res;
    for (int t = 0; t < MAX; t++) {
      if (v[t]) res.push_back(v[t]);
    }
    reverse(begin(res), end(res));
    return res;
  }

  // x を作れるか? TODO:verify
  bool test(Int x) {
    if (x == 0) return true;
    int t = _msb(x);
    if (t >= MAX) return false;
    while (t != -1 && v[t]) t = _msb(x ^= v[t]);
    return x == 0;
  }

  // 作れる x の最大値 TODO:verify
  Int get_max() const {
    Int res = 0;
    for (int t = MAX - 1; t >= 0; t--) res = max(res, res ^ v[t]);
    return res;
  }

  // 行列を標準化する
  void normalize() {
    for (int t = MAX - 1; t >= 0; t--) {
      if (v[t]) {
        for (int u = MAX - 1; u > t; u--) v[u] = min(v[u], v[u] ^ v[t]);
      }
    }
  }

  vector<Int> orthogonal_complement(int N = MAX) {
    normalize();
    vector<int> b;
    for (int t = N - 1; t >= 0; t--) {
      if (v[t]) b.push_back(t);
    }
    int rank = b.size();
    for (int t = N - 1; t >= 0; t--) {
      if (!v[t]) b.push_back(t);
    }
    vector<Int> res(N - rank);
    for (int i = rank; i < N; i++) {
      for (int j = 0; j < N; j++) {
        if (j < rank ? ((v[b[j]] >> b[i]) & 1) : i == j) {
          res[i - rank] |= Int{1} << b[j];
        }
      }
    }
    return res;
  }

  int size() const { return _size; }

  friend ostream& operator<<(ostream& os, const Basis<Int, MAX>& b) {
    os << "{ ";
    for (int i = 0; i < MAX; i++) {
      if (b.v[i]) os << b.v[i] << ", ";
    }
    return os << "}";
  }

 private:
  int _size;
  int _msb(Int x) { return x ? 63 - __builtin_clzll(x) : -1; }
};

/*
 * @brief 掃き出し法
 */
Back to top page