ModInt
(math/modint.hpp)
- View this file on GitHub
- Last update: 2026-07-17 04:56:02+09:00
- Include:
#include "math/modint.hpp"
Overview
A struct for automatic modular arithmetic. It wraps standard integer types to safely and automatically apply modulo operations during addition, subtraction, multiplication, and division. This is highly useful in competitive programming to prevent integer overflow and simplify code syntax.
Two integers represent the same modular value when their difference is
divisible by the modulus. For example, modulo 7, the values 2, 9, and
-5 are equivalent.
ModInt<7> stores all of them as the normalized representative 2. Use
DynamicModInt<id> instead when the modulus is known only at runtime.
Division and Modular Inverses
Modular division is not ordinary integer division. Dividing by b means
multiplying by a value b.inv() such that
For example, modulo 11, the inverse of 3 is 4, because
$3 \cdot 4 = 12$ has remainder 1.
An inverse exists only when the value and modulus are coprime. In particular,
with a prime modulus, every nonzero value has an inverse. This is why prime
moduli such as 998244353 and 1000000007 are common in counting problems.
Template Parameters
template <uint32_t Modulus>
struct ModInt;
template <int Id = 0>
struct DynamicModInt;
Modulus is a compile-time uint32_t value. ModInt<Modulus> is the value
type returned by arithmetic operators and by pow, inv, and raw.
Id distinguishes independent dynamic-modulus types. Every
DynamicModInt<Id> value shares one modulus, set by
DynamicModInt<Id>::set_mod(modulus). Change it only when no existing value of
that type will be used again. The dynamic modulus must be in
[1, 2^31].
Type Aliases
For convenience, the library provides the following common type aliases:
using modint998244353 = ModInt<998244353>;using modint1000000007 = ModInt<1000000007>;
Constructors
| Constructor | Description | Complexity |
|---|---|---|
ModInt() |
Initializes the value to 0. |
$O(1)$ |
template<class Integer> ModInt(Integer v) |
Initializes from any standard integral type. Negative values are normalized, and wide unsigned values are reduced without narrowing first. | $O(1)$ |
DynamicModInt() |
Initializes the value to 0 under the current modulus. |
$O(1)$ |
template<class Integer> DynamicModInt(Integer v) |
Initializes and normalizes an integer under the current modulus. | $O(1)$ |
The integral constructor accepts types such as int, long long,
unsigned long, and std::mt19937::result_type without ambiguous overloads.
Methods
| Method | Description | Complexity |
|---|---|---|
uint32_t val() const |
Returns the stored value in [0, Modulus - 1]. |
$O(1)$ |
ModInt pow(long long n) const |
Computes the n-th power by binary exponentiation. For negative n, raises the modular inverse to the absolute magnitude of n. |
$O(\log (\lvert n\rvert + 1))$ |
ModInt inv() const |
Computes the modular inverse by the extended Euclidean algorithm. The value and modulus must be coprime. | $O(\log(\text{Modulus}))$ |
static uint32_t mod() |
Returns the modulus associated with this type. | $O(1)$ |
static ModInt raw(uint32_t v) |
Constructs directly from v without applying % Modulus. Use only when v < Modulus. |
$O(1)$ |
static void DynamicModInt::set_mod(uint32_t modulus) |
Sets the modulus shared by this tagged dynamic type. | $O(1)$ |
static uint32_t DynamicModInt::mod() |
Returns the current dynamic modulus. | $O(1)$ |
static DynamicModInt DynamicModInt::raw(uint32_t v) |
Constructs directly from a normalized value. | $O(1)$ |
DynamicModInt provides the same val, pow, inv, arithmetic, comparison,
increment, decrement, and stream interfaces as ModInt.
A negative exponent requires the value to have a modular inverse. This includes
the full long long range, so pow(LLONG_MIN) is supported without signed
overflow.
Operators
Binary arithmetic and comparison operators take another
const ModInt<Modulus>&. Compound assignment returns ModInt<Modulus>&;
ordinary arithmetic returns a new ModInt<Modulus> by value. Prefix increment
and decrement return a reference, while postfix increment and decrement return
the previous value.
| Operators | Description | Complexity |
|---|---|---|
+, -, *, +=, -=, *=
|
Performs addition, subtraction, or multiplication with automatic modulo adjustment. | $O(1)$ |
/, /=
|
Multiplies by the modular inverse of the right-hand side. | $O(\log(\text{Modulus}))$ |
++, --
|
Increments or decrements while wrapping around 0 and Modulus - 1. |
$O(1)$ |
==, !=
|
Compares stored values. | $O(1)$ |
<<, >>
|
Outputs the stored value or inputs a standard integer. | $O(1)$ |
Example
#include "math/modint.hpp"
#include <iostream>
using mint = m1une::math::modint998244353;
int main() {
mint a = 1000000000;
mint b = 1000000000;
// Automatic modulo arithmetic
mint c = a * b; // Will not overflow and handles modulo automatically
std::cout << "a * b = " << c << "\n";
// Power
mint d = a.pow(100);
std::cout << "a^100 = " << d << "\n";
mint inverse_cube = mint(5).pow(-3);
std::cout << "5^-3 = " << inverse_cube << "\n";
// Modular inverse & Division
mint e = mint(5).inv();
mint f = a / 5; // Equivalently uses a * mint(5).inv()
std::cout << "Inverse of 5 = " << e << "\n";
std::cout << "a / 5 = " << f << "\n";
return 0;
}
Required by
Geometry Bundle
(geometry/all.hpp)
Lattice-Point Count
(geometry/lattice_point_count.hpp)
Graph All
(graph/all.hpp)
Graph All
(graph/all.hpp)
Graph Counting
(graph/counting.hpp)
Tree All
(graph/tree/all.hpp)
Tree All
(graph/tree/all.hpp)
Tree Distance Frequency
(graph/tree/distance_frequency.hpp)
Tree Distance Frequency
(graph/tree/distance_frequency.hpp)
Math All
(math/all.hpp)
Math All
(math/all.hpp)
Bernoulli Numbers and Power Sums
(math/bernoulli.hpp)
Combinatorial Sequences
(math/combinatorial_sequences.hpp)
Formal Power Series All
(math/fps/all.hpp)
Formal Power Series Composition
(math/fps/composition.hpp)
Compositional Inverse of Formal Power Series
(math/fps/compositional_inverse.hpp)
Convolution
(math/fps/convolution.hpp)
Long Long Convolution
(math/fps/convolution_ll.hpp)
Formal Power Series
(math/fps/formal_power_series.hpp)
Geometric-Sequence Polynomial Evaluation and Interpolation
(math/fps/geometric_sequence_evaluation.hpp)
Polynomial Half-GCD
(math/fps/half_gcd.hpp)
Lagrange Inversion Formula
(math/fps/lagrange_inversion.hpp)
Linear Recurrences and Bostan-Mori
(math/fps/linear_recurrence.hpp)
Multipoint Evaluation and Interpolation
(math/fps/multipoint_evaluation.hpp)
Polynomial Factorization
(math/fps/polynomial_factorization.hpp)
Polynomial Roots over a Finite Field
(math/fps/polynomial_roots.hpp)
Solve Formal Power Series Equation
(math/fps/solve_fps_equation.hpp)
Sparse Formal Power Series
(math/fps/sparse_formal_power_series.hpp)
Multidimensional Convolution
(math/multivariate_convolution.hpp)
Newton Method
(math/newton_method.hpp)
Partition Function
(math/partition_function.hpp)
String Algorithms Bundle
(string/all.hpp)
Wildcard Pattern Matching
(string/wildcard_pattern_matching.hpp)
BigInt
(utilities/bigint.hpp)
Verified with
verify/algo/sequence/number_of_subsequences.test.cpp
verify/ds/dsu/range_parallel_dsu.test.cpp
verify/ds/dsu/unionfind_with_potential_non_commutative_group.test.cpp
verify/ds/dynamic_array/dynamic_lazy_monoid_array.test.cpp
verify/ds/dynamic_tree/rake_compress_link_cut_tree.test.cpp
verify/ds/dynamic_tree/yosupo_point_set_tree_path_composite_sum.test.cpp
verify/ds/range_query/offline_rectangle_add_rectangle_sum.test.cpp
verify/ds/range_query/range_sort_range_composite.test.cpp
verify/ds/segtree/dual_segtree.test.cpp
verify/ds/segtree/dynamic_dual_segtree.test.cpp
verify/ds/segtree/dynamic_lazy_segtree.test.cpp
verify/ds/segtree/lazy_segtree.test.cpp
verify/ds/segtree/persistent_dynamic_lazy_segtree.test.cpp
verify/ds/segtree/persistent_lazy_segtree.test.cpp
verify/ds/segtree/persistent_segtree_beats.test.cpp
verify/ds/segtree/range_update_range_product.test.cpp
verify/ds/segtree/segtree_beats.test.cpp
verify/geometry/centroid.test.cpp
verify/geometry/geometry_algorithms.test.cpp
verify/geometry/lattice_point_count.test.cpp
verify/geometry/rational.test.cpp
verify/graph/counting_spanning_tree_directed.test.cpp
verify/graph/counting_spanning_tree_undirected.test.cpp
verify/graph/cow_game.test.cpp
verify/graph/cow_game.test.cpp
verify/graph/graph_algorithms.test.cpp
verify/graph/graph_algorithms.test.cpp
verify/graph/graph_counting.test.cpp
verify/graph/graph_counting.test.cpp
verify/graph/incremental_scc.test.cpp
verify/graph/range_edge_graph.test.cpp
verify/graph/range_edge_graph.test.cpp
verify/graph/tree/distance_frequency.test.cpp
verify/graph/tree/distance_frequency.test.cpp
verify/graph/tree/tree_algorithms.test.cpp
verify/graph/tree/tree_algorithms.test.cpp
verify/math/bell_number.test.cpp
verify/math/bell_number.test.cpp
verify/math/bernoulli_number.test.cpp
verify/math/bernoulli_number.test.cpp
verify/math/bernoulli_utilities.test.cpp
verify/math/bernoulli_utilities.test.cpp
verify/math/bitwise_and_convolution.test.cpp
verify/math/bitwise_convolution.test.cpp
verify/math/cyclotomic_polynomial.test.cpp
verify/math/divisor_convolution.test.cpp
verify/math/fps/composition.test.cpp
verify/math/fps/composition.test.cpp
verify/math/fps/compositional_inverse.test.cpp
verify/math/fps/compositional_inverse.test.cpp
verify/math/fps/convolution_ll.test.cpp
verify/math/fps/convolution_mod.test.cpp
verify/math/fps/convolution_mod.test.cpp
verify/math/fps/convolution_mod_large.test.cpp
verify/math/fps/convolution_mod_large.test.cpp
verify/math/fps/exp_of_formal_power_series.test.cpp
verify/math/fps/exp_of_formal_power_series.test.cpp
verify/math/fps/exp_of_formal_power_series_sparse.test.cpp
verify/math/fps/exp_of_formal_power_series_sparse.test.cpp
verify/math/fps/find_linear_recurrence.test.cpp
verify/math/fps/find_linear_recurrence.test.cpp
verify/math/fps/fps_algorithms.test.cpp
verify/math/fps/fps_algorithms.test.cpp
verify/math/fps/half_gcd.test.cpp
verify/math/fps/half_gcd.test.cpp
verify/math/fps/inv_of_formal_power_series.test.cpp
verify/math/fps/inv_of_formal_power_series.test.cpp
verify/math/fps/inv_of_formal_power_series_sparse.test.cpp
verify/math/fps/inv_of_formal_power_series_sparse.test.cpp
verify/math/fps/kth_term_of_linearly_recurrent_sequence.test.cpp
verify/math/fps/kth_term_of_linearly_recurrent_sequence.test.cpp
verify/math/fps/lagrange_inversion.test.cpp
verify/math/fps/lagrange_inversion.test.cpp
verify/math/fps/log_of_formal_power_series.test.cpp
verify/math/fps/log_of_formal_power_series.test.cpp
verify/math/fps/log_of_formal_power_series_sparse.test.cpp
verify/math/fps/log_of_formal_power_series_sparse.test.cpp
verify/math/fps/multipoint_evaluation.test.cpp
verify/math/fps/multipoint_evaluation.test.cpp
verify/math/fps/multipoint_evaluation_geometric.test.cpp
verify/math/fps/multipoint_evaluation_geometric.test.cpp
verify/math/fps/polynomial_factorization.test.cpp
verify/math/fps/polynomial_factorization.test.cpp
verify/math/fps/polynomial_interpolation.test.cpp
verify/math/fps/polynomial_interpolation.test.cpp
verify/math/fps/polynomial_interpolation_geometric.test.cpp
verify/math/fps/polynomial_interpolation_geometric.test.cpp
verify/math/fps/polynomial_roots.test.cpp
verify/math/fps/polynomial_roots.test.cpp
verify/math/fps/polynomial_taylor_shift.test.cpp
verify/math/fps/polynomial_taylor_shift.test.cpp
verify/math/fps/pow_of_formal_power_series.test.cpp
verify/math/fps/pow_of_formal_power_series.test.cpp
verify/math/fps/pow_of_formal_power_series_sparse.test.cpp
verify/math/fps/pow_of_formal_power_series_sparse.test.cpp
verify/math/fps/sqrt_of_formal_power_series.test.cpp
verify/math/fps/sqrt_of_formal_power_series.test.cpp
verify/math/fps/sqrt_of_formal_power_series_sparse.test.cpp
verify/math/fps/sqrt_of_formal_power_series_sparse.test.cpp
verify/math/generalized_floor_sum.test.cpp
verify/math/lcm_convolution.test.cpp
verify/math/lucas.test.cpp
verify/math/math_algorithms.test.cpp
verify/math/math_algorithms.test.cpp
verify/math/matrix/adjugate.test.cpp
verify/math/matrix/characteristic_polynomial.test.cpp
verify/math/matrix/hafnian.test.cpp
verify/math/matrix/inverse_matrix.test.cpp
verify/math/matrix/matrix.test.cpp
verify/math/matrix/matrix_det.test.cpp
verify/math/matrix/matrix_product.test.cpp
verify/math/matrix/matrix_rank.test.cpp
verify/math/matrix/pfaffian.test.cpp
verify/math/matrix/sparse_determinant.test.cpp
verify/math/matrix/system_of_linear_equations.test.cpp
verify/math/modint.test.cpp
verify/math/modular_kth_root.test.cpp
verify/math/modular_square_root.test.cpp
verify/math/multivariate_convolution_cyclic.test.cpp
verify/math/multivariate_convolution_cyclic.test.cpp
verify/math/multivariate_convolution_truncated.test.cpp
verify/math/multivariate_convolution_truncated.test.cpp
verify/math/newton_method.test.cpp
verify/math/newton_method.test.cpp
verify/math/partition_function.test.cpp
verify/math/partition_function.test.cpp
verify/math/prefix_sum_of_binom.test.cpp
verify/math/prefix_sum_of_binom_randomized.test.cpp
verify/math/rational.test.cpp
verify/math/repunit.test.cpp
verify/math/set_power_series_exp.test.cpp
verify/math/set_power_series_log.test.cpp
verify/math/stirling_number_of_the_second_kind.test.cpp
verify/math/stirling_number_of_the_second_kind.test.cpp
verify/math/subset_convolution.test.cpp
verify/math/sum_of_multiplicative_function.test.cpp
verify/matroid/linear_matroid_intersection.test.cpp
verify/matroid/matroids.test.cpp
verify/string/string_algorithms.test.cpp
verify/string/wildcard_pattern_matching.test.cpp
verify/utilities/basic_utilities.test.cpp
verify/utilities/bigint_addition.test.cpp
verify/utilities/bigint_division.test.cpp
verify/utilities/bigint_gcd.test.cpp
verify/utilities/bigint_multiplication.test.cpp
Code
#ifndef M1UNE_MATH_MODINT_HPP
#define M1UNE_MATH_MODINT_HPP 1
#include <cassert>
#include <cstdint>
#include <iostream>
#include <type_traits>
#include <utility>
namespace m1une {
namespace math {
template <uint32_t Modulus>
struct ModInt {
static_assert(0 < Modulus, "Modulus must be positive");
private:
uint32_t _v;
public:
static constexpr uint32_t mod() {
return Modulus;
}
static constexpr ModInt raw(uint32_t v) noexcept {
ModInt x;
x._v = v;
return x;
}
constexpr ModInt() noexcept : _v(0) {}
template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
constexpr ModInt(Integer v) noexcept {
if constexpr (std::is_signed_v<Integer>) {
int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(Modulus);
if (x < 0) x += Modulus;
_v = static_cast<uint32_t>(x);
} else {
_v = static_cast<uint32_t>(static_cast<uint64_t>(v) % Modulus);
}
}
constexpr uint32_t val() const noexcept {
return _v;
}
constexpr ModInt& operator++() noexcept {
_v++;
if (_v == Modulus) _v = 0;
return *this;
}
constexpr ModInt& operator--() noexcept {
if (_v == 0) _v = Modulus;
_v--;
return *this;
}
constexpr ModInt operator++(int) noexcept {
ModInt res = *this;
++*this;
return res;
}
constexpr ModInt operator--(int) noexcept {
ModInt res = *this;
--*this;
return res;
}
constexpr ModInt& operator+=(const ModInt& rhs) noexcept {
_v += rhs._v;
if (_v >= Modulus) _v -= Modulus;
return *this;
}
constexpr ModInt& operator-=(const ModInt& rhs) noexcept {
_v -= rhs._v;
if (_v >= Modulus) _v += Modulus;
return *this;
}
constexpr ModInt& operator*=(const ModInt& rhs) noexcept {
uint64_t z = _v;
z *= rhs._v;
_v = static_cast<uint32_t>(z % Modulus);
return *this;
}
constexpr ModInt& operator/=(const ModInt& rhs) noexcept {
return *this *= rhs.inv();
}
constexpr ModInt operator+(const ModInt& rhs) const noexcept {
return ModInt(*this) += rhs;
}
constexpr ModInt operator-(const ModInt& rhs) const noexcept {
return ModInt(*this) -= rhs;
}
constexpr ModInt operator*(const ModInt& rhs) const noexcept {
return ModInt(*this) *= rhs;
}
constexpr ModInt operator/(const ModInt& rhs) const noexcept {
return ModInt(*this) /= rhs;
}
constexpr bool operator==(const ModInt& rhs) const noexcept {
return _v == rhs._v;
}
constexpr bool operator!=(const ModInt& rhs) const noexcept {
return _v != rhs._v;
}
constexpr ModInt pow(long long n) const noexcept {
ModInt res = raw(1 % Modulus);
ModInt x = n < 0 ? inv() : *this;
uint64_t exponent = n < 0 ? uint64_t(-(n + 1)) + 1 : uint64_t(n);
while (exponent > 0) {
if (exponent & 1) res *= x;
x *= x;
exponent >>= 1;
}
return res;
}
constexpr ModInt inv() const noexcept {
int64_t a = _v, b = Modulus, u = 1, v = 0;
while (b) {
int64_t t = a / b;
a -= t * b;
std::swap(a, b);
u -= t * v;
std::swap(u, v);
}
assert(a == 1);
u %= Modulus;
if (u < 0) u += Modulus;
return raw(static_cast<uint32_t>(u));
}
friend std::ostream& operator<<(std::ostream& os, const ModInt& rhs) {
return os << rhs._v;
}
friend std::istream& operator>>(std::istream& is, ModInt& rhs) {
long long v;
is >> v;
rhs = ModInt(v);
return is;
}
};
using modint998244353 = ModInt<998244353>;
using modint1000000007 = ModInt<1000000007>;
template <int Id = 0>
struct DynamicModInt {
private:
uint32_t _v;
inline static uint32_t _mod = 1;
public:
static uint32_t mod() noexcept {
return _mod;
}
static void set_mod(uint32_t modulus) noexcept {
assert(modulus > 0);
assert(modulus <= uint32_t(1) << 31);
_mod = modulus;
}
static DynamicModInt raw(uint32_t v) noexcept {
assert(v < _mod);
DynamicModInt x;
x._v = v;
return x;
}
DynamicModInt() noexcept : _v(0) {}
template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
DynamicModInt(Integer v) noexcept {
if constexpr (std::is_signed_v<Integer>) {
int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(_mod);
if (x < 0) x += _mod;
_v = static_cast<uint32_t>(x);
} else {
_v = static_cast<uint32_t>(static_cast<uint64_t>(v) % _mod);
}
}
uint32_t val() const noexcept {
return _v;
}
DynamicModInt& operator++() noexcept {
_v++;
if (_v == _mod) _v = 0;
return *this;
}
DynamicModInt& operator--() noexcept {
if (_v == 0) _v = _mod;
_v--;
return *this;
}
DynamicModInt operator++(int) noexcept {
DynamicModInt result = *this;
++*this;
return result;
}
DynamicModInt operator--(int) noexcept {
DynamicModInt result = *this;
--*this;
return result;
}
DynamicModInt& operator+=(const DynamicModInt& rhs) noexcept {
_v += rhs._v;
if (_v >= _mod) _v -= _mod;
return *this;
}
DynamicModInt& operator-=(const DynamicModInt& rhs) noexcept {
_v -= rhs._v;
if (_v >= _mod) _v += _mod;
return *this;
}
DynamicModInt& operator*=(const DynamicModInt& rhs) noexcept {
_v = static_cast<uint32_t>(uint64_t(_v) * rhs._v % _mod);
return *this;
}
DynamicModInt& operator/=(const DynamicModInt& rhs) noexcept {
return *this *= rhs.inv();
}
DynamicModInt operator+(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) += rhs;
}
DynamicModInt operator-(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) -= rhs;
}
DynamicModInt operator*(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) *= rhs;
}
DynamicModInt operator/(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) /= rhs;
}
bool operator==(const DynamicModInt& rhs) const noexcept {
return _v == rhs._v;
}
bool operator!=(const DynamicModInt& rhs) const noexcept {
return _v != rhs._v;
}
DynamicModInt pow(long long exponent) const noexcept {
DynamicModInt result = raw(1 % _mod);
DynamicModInt base = exponent < 0 ? inv() : *this;
uint64_t magnitude =
exponent < 0 ? uint64_t(-(exponent + 1)) + 1 : uint64_t(exponent);
while (magnitude > 0) {
if (magnitude & 1) result *= base;
base *= base;
magnitude >>= 1;
}
return result;
}
DynamicModInt inv() const noexcept {
int64_t a = _v, b = _mod, u = 1, v = 0;
while (b) {
int64_t quotient = a / b;
a -= quotient * b;
std::swap(a, b);
u -= quotient * v;
std::swap(u, v);
}
assert(a == 1);
u %= _mod;
if (u < 0) u += _mod;
return raw(static_cast<uint32_t>(u));
}
friend std::ostream& operator<<(std::ostream& os, const DynamicModInt& rhs) {
return os << rhs._v;
}
friend std::istream& operator>>(std::istream& is, DynamicModInt& rhs) {
long long value;
is >> value;
rhs = DynamicModInt(value);
return is;
}
};
} // namespace math
} // namespace m1une
#endif // M1UNE_MATH_MODINT_HPP#line 1 "math/modint.hpp"
#include <cassert>
#include <cstdint>
#include <iostream>
#include <type_traits>
#include <utility>
namespace m1une {
namespace math {
template <uint32_t Modulus>
struct ModInt {
static_assert(0 < Modulus, "Modulus must be positive");
private:
uint32_t _v;
public:
static constexpr uint32_t mod() {
return Modulus;
}
static constexpr ModInt raw(uint32_t v) noexcept {
ModInt x;
x._v = v;
return x;
}
constexpr ModInt() noexcept : _v(0) {}
template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
constexpr ModInt(Integer v) noexcept {
if constexpr (std::is_signed_v<Integer>) {
int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(Modulus);
if (x < 0) x += Modulus;
_v = static_cast<uint32_t>(x);
} else {
_v = static_cast<uint32_t>(static_cast<uint64_t>(v) % Modulus);
}
}
constexpr uint32_t val() const noexcept {
return _v;
}
constexpr ModInt& operator++() noexcept {
_v++;
if (_v == Modulus) _v = 0;
return *this;
}
constexpr ModInt& operator--() noexcept {
if (_v == 0) _v = Modulus;
_v--;
return *this;
}
constexpr ModInt operator++(int) noexcept {
ModInt res = *this;
++*this;
return res;
}
constexpr ModInt operator--(int) noexcept {
ModInt res = *this;
--*this;
return res;
}
constexpr ModInt& operator+=(const ModInt& rhs) noexcept {
_v += rhs._v;
if (_v >= Modulus) _v -= Modulus;
return *this;
}
constexpr ModInt& operator-=(const ModInt& rhs) noexcept {
_v -= rhs._v;
if (_v >= Modulus) _v += Modulus;
return *this;
}
constexpr ModInt& operator*=(const ModInt& rhs) noexcept {
uint64_t z = _v;
z *= rhs._v;
_v = static_cast<uint32_t>(z % Modulus);
return *this;
}
constexpr ModInt& operator/=(const ModInt& rhs) noexcept {
return *this *= rhs.inv();
}
constexpr ModInt operator+(const ModInt& rhs) const noexcept {
return ModInt(*this) += rhs;
}
constexpr ModInt operator-(const ModInt& rhs) const noexcept {
return ModInt(*this) -= rhs;
}
constexpr ModInt operator*(const ModInt& rhs) const noexcept {
return ModInt(*this) *= rhs;
}
constexpr ModInt operator/(const ModInt& rhs) const noexcept {
return ModInt(*this) /= rhs;
}
constexpr bool operator==(const ModInt& rhs) const noexcept {
return _v == rhs._v;
}
constexpr bool operator!=(const ModInt& rhs) const noexcept {
return _v != rhs._v;
}
constexpr ModInt pow(long long n) const noexcept {
ModInt res = raw(1 % Modulus);
ModInt x = n < 0 ? inv() : *this;
uint64_t exponent = n < 0 ? uint64_t(-(n + 1)) + 1 : uint64_t(n);
while (exponent > 0) {
if (exponent & 1) res *= x;
x *= x;
exponent >>= 1;
}
return res;
}
constexpr ModInt inv() const noexcept {
int64_t a = _v, b = Modulus, u = 1, v = 0;
while (b) {
int64_t t = a / b;
a -= t * b;
std::swap(a, b);
u -= t * v;
std::swap(u, v);
}
assert(a == 1);
u %= Modulus;
if (u < 0) u += Modulus;
return raw(static_cast<uint32_t>(u));
}
friend std::ostream& operator<<(std::ostream& os, const ModInt& rhs) {
return os << rhs._v;
}
friend std::istream& operator>>(std::istream& is, ModInt& rhs) {
long long v;
is >> v;
rhs = ModInt(v);
return is;
}
};
using modint998244353 = ModInt<998244353>;
using modint1000000007 = ModInt<1000000007>;
template <int Id = 0>
struct DynamicModInt {
private:
uint32_t _v;
inline static uint32_t _mod = 1;
public:
static uint32_t mod() noexcept {
return _mod;
}
static void set_mod(uint32_t modulus) noexcept {
assert(modulus > 0);
assert(modulus <= uint32_t(1) << 31);
_mod = modulus;
}
static DynamicModInt raw(uint32_t v) noexcept {
assert(v < _mod);
DynamicModInt x;
x._v = v;
return x;
}
DynamicModInt() noexcept : _v(0) {}
template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
DynamicModInt(Integer v) noexcept {
if constexpr (std::is_signed_v<Integer>) {
int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(_mod);
if (x < 0) x += _mod;
_v = static_cast<uint32_t>(x);
} else {
_v = static_cast<uint32_t>(static_cast<uint64_t>(v) % _mod);
}
}
uint32_t val() const noexcept {
return _v;
}
DynamicModInt& operator++() noexcept {
_v++;
if (_v == _mod) _v = 0;
return *this;
}
DynamicModInt& operator--() noexcept {
if (_v == 0) _v = _mod;
_v--;
return *this;
}
DynamicModInt operator++(int) noexcept {
DynamicModInt result = *this;
++*this;
return result;
}
DynamicModInt operator--(int) noexcept {
DynamicModInt result = *this;
--*this;
return result;
}
DynamicModInt& operator+=(const DynamicModInt& rhs) noexcept {
_v += rhs._v;
if (_v >= _mod) _v -= _mod;
return *this;
}
DynamicModInt& operator-=(const DynamicModInt& rhs) noexcept {
_v -= rhs._v;
if (_v >= _mod) _v += _mod;
return *this;
}
DynamicModInt& operator*=(const DynamicModInt& rhs) noexcept {
_v = static_cast<uint32_t>(uint64_t(_v) * rhs._v % _mod);
return *this;
}
DynamicModInt& operator/=(const DynamicModInt& rhs) noexcept {
return *this *= rhs.inv();
}
DynamicModInt operator+(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) += rhs;
}
DynamicModInt operator-(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) -= rhs;
}
DynamicModInt operator*(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) *= rhs;
}
DynamicModInt operator/(const DynamicModInt& rhs) const noexcept {
return DynamicModInt(*this) /= rhs;
}
bool operator==(const DynamicModInt& rhs) const noexcept {
return _v == rhs._v;
}
bool operator!=(const DynamicModInt& rhs) const noexcept {
return _v != rhs._v;
}
DynamicModInt pow(long long exponent) const noexcept {
DynamicModInt result = raw(1 % _mod);
DynamicModInt base = exponent < 0 ? inv() : *this;
uint64_t magnitude =
exponent < 0 ? uint64_t(-(exponent + 1)) + 1 : uint64_t(exponent);
while (magnitude > 0) {
if (magnitude & 1) result *= base;
base *= base;
magnitude >>= 1;
}
return result;
}
DynamicModInt inv() const noexcept {
int64_t a = _v, b = _mod, u = 1, v = 0;
while (b) {
int64_t quotient = a / b;
a -= quotient * b;
std::swap(a, b);
u -= quotient * v;
std::swap(u, v);
}
assert(a == 1);
u %= _mod;
if (u < 0) u += _mod;
return raw(static_cast<uint32_t>(u));
}
friend std::ostream& operator<<(std::ostream& os, const DynamicModInt& rhs) {
return os << rhs._v;
}
friend std::istream& operator>>(std::istream& is, DynamicModInt& rhs) {
long long value;
is >> value;
rhs = DynamicModInt(value);
return is;
}
};
} // namespace math
} // namespace m1une