This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "tools/monoid.hpp"
They are typical monoids.
(1) template <typename M> struct monoid::max;
(2) template <typename M, M E> struct monoid::max;
It is a monoid $(M, \max, E)$.
<M>
is a built-in integral type, let $E$ be std::numeric_limits<M>::min()
.<M>
is a built-in floating-point type, let $E$ be -std::numeric_limits<M>::infinity()
.using T = M;
It is an alias for <M>
.
static M op(M x, M y);
It returns $\max(x, y)$.
static M e();
It returns $E$.
(1) template <typename M> struct monoid::min;
(2) template <typename M, M E> struct monoid::min;
It is a monoid $(M, \min, E)$.
<M>
is a built-in integral type, let $E$ be std::numeric_limits<M>::max()
.<M>
is a built-in floating-point type, let $E$ be std::numeric_limits<M>::infinity()
.using T = M;
It is an alias for <M>
.
static M op(M x, M y);
It returns $\min(x, y)$.
static M e();
It returns $E$.
template <typename M> struct monoid::multiplies;
It is a monoid $(M, \times, 1)$.
x
is <M>
and y
is <M>
, then x * y
is also <M>
.x
in <M>
, y
in <M>
and z
in <M>
, (x * y) * z
$=$ x * (y * z)
.x
in <M>
, M(1) * x
$=$ x * M(1)
$=$ x
.using T = M;
It is an alias for <M>
.
static M op(M x, M y);
It returns x * y
.
x * y
static M e();
It returns M(1)
.
M(1)
template <typename M> struct monoid::gcd;
It is a monoid $(M, \gcd, 0)$. Note that we define $\gcd(a, 0) = a$, $\gcd(0, b) = b$ and $\gcd(0, 0) = 0$ in this monoid.
tools::gcd(x, y)
is defined for x
and y
of type <M>
. In particular, <M>
is neither a built-in floating-point type nor bool
.using T = M;
It is an alias for <M>
.
static M op(M x, M y);
It returns tools::gcd(x, y)
.
For a built-in integral type <M>
, this is equivalent to returning std::gcd(x, y)
.
tools::gcd(x, y)
static M e();
It returns M(0)
.
M(0)
.template <typename M, M E> struct monoid::update;
It is a monoid $(M, U, E)$ where
\[\begin{align*} U(x, y) &= \left\{\begin{array}{ll} y & \text{(if $x = E$)}\\ x & \text{(if $x \neq E$)} \end{array}\right. \end{align*}\]<M>
is a built-in integral type.using T = M;
It is an alias for <M>
.
static M op(M x, M y);
It returns $U(x, y)$.
static M e();
It returns E
.
#ifndef TOOLS_MONOID_HPP
#define TOOLS_MONOID_HPP
#include <type_traits>
#include <algorithm>
#include <limits>
#include <cassert>
#include "tools/gcd.hpp"
namespace tools {
namespace monoid {
template <typename M, M ...dummy>
struct max;
template <typename M>
struct max<M> {
static_assert(::std::is_arithmetic_v<M>, "M must be a built-in arithmetic type.");
using T = M;
static T op(const T lhs, const T rhs) {
return ::std::max(lhs, rhs);
}
static T e() {
if constexpr (::std::is_integral_v<M>) {
return ::std::numeric_limits<M>::min();
} else {
return -::std::numeric_limits<M>::infinity();
}
}
};
template <typename M, M E>
struct max<M, E> {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
assert(E <= lhs);
assert(E <= rhs);
return ::std::max(lhs, rhs);
}
static T e() {
return E;
}
};
template <typename M, M ...dummy>
struct min;
template <typename M>
struct min<M> {
static_assert(::std::is_arithmetic_v<M>, "M must be a built-in arithmetic type.");
using T = M;
static T op(const T lhs, const T rhs) {
return ::std::min(lhs, rhs);
}
static T e() {
if constexpr (::std::is_integral_v<M>) {
return ::std::numeric_limits<M>::max();
} else {
return ::std::numeric_limits<M>::infinity();
}
}
};
template <typename M, M E>
struct min<M, E> {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
assert(lhs <= E);
assert(rhs <= E);
return ::std::min(lhs, rhs);
}
static T e() {
return E;
}
};
template <typename M>
struct multiplies {
private:
using VR = ::std::conditional_t<::std::is_arithmetic_v<M>, const M, const M&>;
public:
using T = M;
static T op(VR lhs, VR rhs) {
return lhs * rhs;
}
static T e() {
return T(1);
}
};
template <>
struct multiplies<bool> {
using T = bool;
static T op(const bool lhs, const bool rhs) {
return lhs && rhs;
}
static T e() {
return true;
}
};
template <typename M>
struct gcd {
private:
static_assert(!::std::is_arithmetic_v<M> || (::std::is_integral_v<M> && !::std::is_same_v<M, bool>), "If M is a built-in arithmetic type, it must be integral except for bool.");
using VR = ::std::conditional_t<::std::is_arithmetic_v<M>, const M, const M&>;
public:
using T = M;
static T op(VR lhs, VR rhs) {
return ::tools::gcd(lhs, rhs);
}
static T e() {
return T(0);
}
};
template <typename M, M E>
struct update {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
return lhs == E ? rhs : lhs;
}
static T e() {
return E;
}
};
}
}
#endif
#line 1 "tools/monoid.hpp"
#include <type_traits>
#include <algorithm>
#include <limits>
#include <cassert>
#line 1 "tools/gcd.hpp"
#line 5 "tools/gcd.hpp"
#include <numeric>
namespace tools {
template <typename M, typename N>
constexpr ::std::common_type_t<M, N> gcd(const M m, const N n) {
return ::std::gcd(m, n);
}
}
#line 9 "tools/monoid.hpp"
namespace tools {
namespace monoid {
template <typename M, M ...dummy>
struct max;
template <typename M>
struct max<M> {
static_assert(::std::is_arithmetic_v<M>, "M must be a built-in arithmetic type.");
using T = M;
static T op(const T lhs, const T rhs) {
return ::std::max(lhs, rhs);
}
static T e() {
if constexpr (::std::is_integral_v<M>) {
return ::std::numeric_limits<M>::min();
} else {
return -::std::numeric_limits<M>::infinity();
}
}
};
template <typename M, M E>
struct max<M, E> {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
assert(E <= lhs);
assert(E <= rhs);
return ::std::max(lhs, rhs);
}
static T e() {
return E;
}
};
template <typename M, M ...dummy>
struct min;
template <typename M>
struct min<M> {
static_assert(::std::is_arithmetic_v<M>, "M must be a built-in arithmetic type.");
using T = M;
static T op(const T lhs, const T rhs) {
return ::std::min(lhs, rhs);
}
static T e() {
if constexpr (::std::is_integral_v<M>) {
return ::std::numeric_limits<M>::max();
} else {
return ::std::numeric_limits<M>::infinity();
}
}
};
template <typename M, M E>
struct min<M, E> {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
assert(lhs <= E);
assert(rhs <= E);
return ::std::min(lhs, rhs);
}
static T e() {
return E;
}
};
template <typename M>
struct multiplies {
private:
using VR = ::std::conditional_t<::std::is_arithmetic_v<M>, const M, const M&>;
public:
using T = M;
static T op(VR lhs, VR rhs) {
return lhs * rhs;
}
static T e() {
return T(1);
}
};
template <>
struct multiplies<bool> {
using T = bool;
static T op(const bool lhs, const bool rhs) {
return lhs && rhs;
}
static T e() {
return true;
}
};
template <typename M>
struct gcd {
private:
static_assert(!::std::is_arithmetic_v<M> || (::std::is_integral_v<M> && !::std::is_same_v<M, bool>), "If M is a built-in arithmetic type, it must be integral except for bool.");
using VR = ::std::conditional_t<::std::is_arithmetic_v<M>, const M, const M&>;
public:
using T = M;
static T op(VR lhs, VR rhs) {
return ::tools::gcd(lhs, rhs);
}
static T e() {
return T(0);
}
};
template <typename M, M E>
struct update {
static_assert(::std::is_integral_v<M>, "M must be a built-in integral type.");
using T = M;
static T op(const T lhs, const T rhs) {
return lhs == E ? rhs : lhs;
}
static T e() {
return E;
}
};
}
}