This documentation is automatically generated by online-judge-tools/verification-helper
#include "Math/pfaffian.hpp"#pragma once
#include "Math/matrix.hpp"
template <typename T> T Pfaffian(Matrix<T> &a) {
int n = a.h;
assert(n == a.w and n % 2 == 0);
T ret = 1;
for (int i = 1; i < n; i += 2) {
rep(j, i, n) if (a[j][i - 1] != 0) {
swap(a[j], a[i]);
for (auto &v : a.val)
swap(v[j], v[i]);
if (i != j)
ret = -ret;
break;
}
if (a[i][i - 1] == 0)
return 0;
ret *= -a[i][i - 1];
T inv = T(1) / a[i][i - 1];
rep(j, i + 1, n) {
T z = a[j][i - 1] * inv;
rep(k, 0, n) a[j][k] -= z * a[i][k];
}
inv = T(1) / a[i - 1][i];
rep(j, i + 1, n) {
T z = a[i - 1][j] * inv;
rep(k, 0, n) a[k][j] -= z * a[k][i];
}
}
return ret;
}
/**
* @brief Pfaffian
*/#line 2 "Math/matrix.hpp"
template <class T> struct Matrix {
int h, w;
vector<vector<T>> val;
T det;
Matrix() {}
Matrix(int n) : h(n), w(n), val(vector<vector<T>>(n, vector<T>(n))) {}
Matrix(int n, int m)
: h(n), w(m), val(vector<vector<T>>(n, vector<T>(m))) {}
vector<T> &operator[](const int i) {
return val[i];
}
Matrix &operator+=(const Matrix &m) {
assert(h == m.h and w == m.w);
rep(i, 0, h) rep(j, 0, w) val[i][j] += m.val[i][j];
return *this;
}
Matrix &operator-=(const Matrix &m) {
assert(h == m.h and w == m.w);
rep(i, 0, h) rep(j, 0, w) val[i][j] -= m.val[i][j];
return *this;
}
Matrix &operator*=(const Matrix &m) {
assert(w == m.h);
Matrix<T> res(h, m.w);
rep(i, 0, h) rep(j, 0, m.w) rep(k, 0, w) res.val[i][j] +=
val[i][k] * m.val[k][j];
*this = res;
return *this;
}
Matrix operator+(const Matrix &m) const {
return Matrix(*this) += m;
}
Matrix operator-(const Matrix &m) const {
return Matrix(*this) -= m;
}
Matrix operator*(const Matrix &m) const {
return Matrix(*this) *= m;
}
Matrix pow(ll k) {
Matrix<T> res(h, h), c = *this;
rep(i, 0, h) res.val[i][i] = 1;
while (k) {
if (k & 1)
res *= c;
c *= c;
k >>= 1;
}
return res;
}
vector<int> gauss(int c = -1) {
det = 1;
if (val.empty())
return {};
if (c == -1)
c = w;
int cur = 0;
vector<int> res;
rep(i, 0, c) {
if (cur == h)
break;
rep(j, cur, h) if (val[j][i] != 0) {
swap(val[cur], val[j]);
if (cur != j)
det *= -1;
break;
}
det *= val[cur][i];
if (val[cur][i] == 0)
continue;
rep(j, 0, h) if (j != cur) {
T z = val[j][i] / val[cur][i];
rep(k, i, w) val[j][k] -= val[cur][k] * z;
}
res.push_back(i);
cur++;
}
return res;
}
Matrix inv() {
assert(h == w);
Matrix base(h, h * 2), res(h, h);
rep(i, 0, h) rep(j, 0, h) base[i][j] = val[i][j];
rep(i, 0, h) base[i][h + i] = 1;
base.gauss(h);
det = base.det;
rep(i, 0, h) rep(j, 0, h) res[i][j] = base[i][h + j] / base[i][i];
return res;
}
bool operator==(const Matrix &m) {
assert(h == m.h and w == m.w);
rep(i, 0, h) rep(j, 0, w) if (val[i][j] != m.val[i][j]) return false;
return true;
}
bool operator!=(const Matrix &m) {
assert(h == m.h and w == m.w);
rep(i, 0, h) rep(j, 0, w) if (val[i][j] == m.val[i][j]) return false;
return true;
}
friend istream &operator>>(istream &is, Matrix &m) {
rep(i, 0, m.h) rep(j, 0, m.w) is >> m[i][j];
return is;
}
friend ostream &operator<<(ostream &os, Matrix &m) {
rep(i, 0, m.h) {
rep(j, 0, m.w) os << m[i][j]
<< (j == m.w - 1 and i != m.h - 1 ? '\n' : ' ');
}
return os;
}
};
/**
* @brief Matrix
*/
#line 3 "Math/pfaffian.hpp"
template <typename T> T Pfaffian(Matrix<T> &a) {
int n = a.h;
assert(n == a.w and n % 2 == 0);
T ret = 1;
for (int i = 1; i < n; i += 2) {
rep(j, i, n) if (a[j][i - 1] != 0) {
swap(a[j], a[i]);
for (auto &v : a.val)
swap(v[j], v[i]);
if (i != j)
ret = -ret;
break;
}
if (a[i][i - 1] == 0)
return 0;
ret *= -a[i][i - 1];
T inv = T(1) / a[i][i - 1];
rep(j, i + 1, n) {
T z = a[j][i - 1] * inv;
rep(k, 0, n) a[j][k] -= z * a[i][k];
}
inv = T(1) / a[i - 1][i];
rep(j, i + 1, n) {
T z = a[i - 1][j] * inv;
rep(k, 0, n) a[k][j] -= z * a[k][i];
}
}
return ret;
}
/**
* @brief Pfaffian
*/