#line 1 "other/ms.cc" // #undef _GLIBCXX_DEBUG // #define NDEBUG #include // #include "lib/alias" // #include "lib/cxx20" // #include "lib/direct" // #include "lib/opt" // #include "lib/sys" // #include "lib/utils" // signed main() { // using namespace workspace; // io_setup(15); // /* given // case_info.read(); //*/ // /* unspecified // case_info.total = -1; //*/ // return case_info.iterate(); // } #line 2 "Library/src/algebra/linear/matrix.hpp" /** * @file matrix.hpp * @brief Matrix * @date 2021-02-15 * * */ #line 13 "Library/src/algebra/linear/matrix.hpp" namespace workspace { /** * @brief Fixed size matrix. * * @tparam _Scalar * @tparam _Rows Number of rows * @tparam _Cols Number of columns */ template class matrix { public: _Scalar __data[_Rows][_Cols] = {}; using value_type = _Scalar; using size_type = std::size_t; constexpr static matrix eye() { static_assert(_Rows == _Cols); matrix __e; for (size_type __d = 0; __d != _Rows; ++__d) __e.__data[__d][__d] = 1; return __e; } constexpr operator decltype((__data))() { return __data; } constexpr operator decltype(std::declval().__data) const&() const { return __data; } constexpr auto begin() { return __data; } constexpr auto begin() const { return __data; } constexpr auto end() { return __data + _Rows; } constexpr auto end() const { return __data + _Rows; } constexpr size_type rows() const { return _Rows; } constexpr size_type cols() const { return _Cols; } constexpr auto transpose() const { matrix<_Scalar, _Cols, _Rows> __t; for (size_type __r = 0; __r != _Rows; ++__r) for (size_type __c = 0; __c != _Cols; ++__c) __t.__data[__c][__r] = __data[__r][__c]; return __t; } constexpr matrix operator+() const { return *this; } constexpr matrix operator-() const { matrix __cp = *this; for (auto& __v : __cp.__data) for (auto& __e : __v) __e = -__e; return __cp; } template constexpr matrix& operator+=(const _Matrix& __x) { auto __m = std::min(_Rows, __x.rows()); auto __n = std::min(_Cols, __x.cols()); for (size_type __r = 0; __r != __m; ++__r) for (size_type __c = 0; __c != __n; ++__c) __data[__r][__c] += __x[__r][__c]; return *this; } template constexpr matrix operator+(const _Matrix& __x) const { return matrix(*this) += __x; } template constexpr matrix& operator-=(const _Matrix& __x) { auto __m = std::min(_Rows, __x.rows()); auto __n = std::min(_Cols, __x.cols()); for (size_type __r = 0; __r != __m; ++__r) for (size_type __c = 0; __c != __n; ++__c) __data[__r][__c] -= __x[__r][__c]; return *this; } template constexpr matrix operator-(const _Matrix& __x) const { return matrix(*this) -= __x; } template constexpr matrix& operator*=(const matrix<_Scalar2, _Cols, _Cols>& __x) { if (this == &__x) return operator=(operator*(__x)); for (auto& __r : __data) { _Scalar __tmp[_Cols] = {}; auto __v = *__x.__data; for (auto& __w : __tmp) { auto __i = __v++; for (const auto& __e : __r) __w += __e * *__i, __i += _Cols; } auto __w = __tmp; for (auto& __e : __r) __e = std::move(*__w++); } return *this; } template constexpr matrix<_Scalar, _Rows, _Cols2> operator*( const matrix<_Scalar2, _Cols, _Cols2>& __x) const { matrix<_Scalar, _Rows, _Cols2> __m; auto __w = *__m.__data; for (const auto& __r : __data) for (auto __v = *__x.__data, __end = __v + _Cols2; __v != __end; ++__w) { auto __i = __v++; for (const auto& __e : __r) *__w += __e * *__i, __i += _Cols2; } return __m; } template constexpr typename std::enable_if::value, matrix<_Scalar>>::type operator*(const _Matrix& __x) const { assert(_Cols <= __x.rows()); matrix<_Scalar> __m(_Rows, __x.cols()); for (size_type __r = 0; __r != _Rows; ++__r) for (size_type __i = 0; __i != __x.cols(); ++__i) for (size_type __c = 0; __c != _Cols; ++__c) __m[__r][__i] += __data[__r][__c] * __x[__c][__i]; return __m; } constexpr matrix& operator*=(const value_type& __x) { for (auto& __v : __data) for (auto& __e : __v) __e *= __x; return *this; } constexpr matrix operator*(const value_type& __x) const { return matrix(*this) *= __x; } constexpr matrix& operator/=(const value_type& __x) { assert(__x != value_type(0)); for (auto& __v : __data) for (auto& __e : __v) __e /= __x; return *this; } constexpr matrix operator/(const value_type& __x) const { return matrix(*this) /= __x; } template constexpr matrix pow(_Int __e) const { static_assert(_Rows == _Cols); assert(0 <= __e); matrix __m = eye(); for (matrix __cp = *this; __e; __cp *= __cp, __e >>= 1) if (__e & 1) __m *= __cp; return __m; } template constexpr friend _Os& operator<<(_Os& __os, const matrix& __x) { for (auto __i = __x.begin(); __i != __x.end(); ++__i, __os << '\n') for (size_type __c = 0; __c != _Cols; ++__c) __c ? void(__os << ' ') : (void)0, __os << *(*__i + __c); return __os; } }; // namespace workspace /** * @brief Dynamic matrix. * * @tparam _Scalar * @tparam _Rows Number of rows * @tparam _Cols Number of columns */ template class matrix<_Scalar, 0, 0> : public std::valarray> { using base = std::valarray>; using row_type = typename base::value_type; public: using value_type = _Scalar; using size_type = std::size_t; using base::operator[]; static matrix eye(size_type __n) { matrix __e(__n, __n); for (size_type __d = 0; __d != __n; ++__d) __e[__d][__d] = 1; return __e; } matrix() = default; matrix(size_type __n) : matrix(__n, __n) {} matrix(size_type __m, size_type __n) : base(row_type(__n), __m) {} template ::value && !std::is_constructible::value>::type> matrix(_Tp&& __x) : base(__x) {} matrix(std::initializer_list __x) : base(__x) {} size_type rows() const { return base::size(); } size_type cols() const { return rows() ? operator[](0).size() : 0; } matrix transpose() const { matrix __t(cols(), rows()); for (size_type __r = 0; __r != rows(); ++__r) for (size_type __c = 0; __c != cols(); ++__c) __t[__c][__r] = operator[](__r)[__c]; return __t; } void resize(size_type __m, size_type __n) { matrix __t(__m, __n); if (rows() < __m) __m = rows(); if (cols() < __n) __n = cols(); for (size_type __r = 0; __r != __m; ++__r) for (size_type __c = 0; __c != __n; ++__c) __t[__r][__c] = std::move(operator[](__r)[__c]); base::swap(__t); } // binary operators {{ template struct is_valarray_based : std::false_type {}; template struct is_valarray_based< _Matrix, typename std::enable_if()[0])>::type>::value>::type> : std::true_type {}; template typename std::enable_if::value, matrix&>::type operator*=(_Matrix&& __x) { return operator=(operator*(std::forward<_Matrix>(__x))); } template typename std::enable_if::value, matrix>::type operator*(const _Matrix& __x) const { assert(cols() <= __x.rows()); matrix __m(rows(), __x.cols()); if constexpr (is_valarray_based<_Matrix>::value) for (size_type __r = 0; __r != rows(); ++__r) for (size_type __c = 0; __c != cols(); ++__c) __m[__r] += operator[](__r)[__c] * __x[__c]; else for (size_type __r = 0; __r != rows(); ++__r) for (size_type __c = 0; __c != cols(); ++__c) for (size_type __i = 0; __i != __x.cols(); ++__i) __m[__r][__i] += operator[](__r)[__c] * __x[__c][__i]; return __m; } matrix& operator*=(const value_type& __x) { for (size_type __r = 0; __r != rows(); ++__r) operator[](__r).operator*=(__x); return *this; } matrix operator*(const value_type& __x) const { return matrix(*this) *= __x; } friend matrix operator*(const value_type& __x, matrix __i) { for (size_type __r = 0; __r != __i.rows(); ++__r) __i.operator[](__r) = __x * __i.operator[](__r); return __i; } matrix& operator/=(const value_type& __x) { assert(__x != value_type(0)); for (size_type __r = 0; __r != rows(); ++__r) operator[](__r).operator/=(__x); return *this; } matrix operator/(const value_type& __x) const { return matrix(*this) /= __x; } // }} binary operators template matrix pow(_Int __e) const { assert(0 <= __e); matrix __m = eye(rows()); for (matrix __cp = *this; __e; __cp *= __cp, __e >>= 1) if (__e & 1) __m *= __cp; return __m; } // template friend _Is& operator>>(_Is& __is, matrix& __x) { // for (size_type __r = 0; __r != __x.rows(); ++__r) // for (size_type __c = 0; __c != __x.cols(); ++__c) // __is >> __x.operator[](__r).operator[](__c); // return __is; // } template friend _Os& operator<<(_Os& __os, const matrix& __x) { for (size_type __r = 0; __r != __x.rows(); ++__r, __os << '\n') for (size_type __c = 0; __c != __x.cols(); ++__c) __c ? void(__os << ' ') : (void)0, __os << __x.operator[](__r).operator[](__c); return __os; } }; } // namespace workspace #line 2 "Library/src/data_structure/segment_tree/basic.hpp" /** * @file basic.hpp * @brief Segment Tree */ #line 10 "Library/src/data_structure/segment_tree/basic.hpp" #if __cplusplus >= 201703L #include #endif #line 2 "Library/src/algebra/system/monoid.hpp" /* * @file monoid.hpp * @brief Monoid */ #line 9 "Library/src/algebra/system/monoid.hpp" namespace workspace { template struct min_monoid { using value_type = T; static T min, max; T value; min_monoid() : value(max) {} min_monoid(const T &value) : value(value) {} operator T() const { return value; } min_monoid operator+(const min_monoid &rhs) const { return value < rhs.value ? *this : rhs; } min_monoid operator*(const E &rhs) const; }; template T min_monoid::min = std::numeric_limits::min() / 2; template T min_monoid::max = std::numeric_limits::max() / 2; template struct max_monoid : min_monoid { using base = min_monoid; using base::min_monoid; max_monoid() : base(base::min) {} max_monoid operator+(const max_monoid &rhs) const { return !(base::value < rhs.value) ? *this : rhs; } max_monoid operator*(const E &rhs) const; }; } // namespace workspace #line 16 "Library/src/data_structure/segment_tree/basic.hpp" namespace workspace { /** * @tparam Monoid `operator+`, `operator=` * @tparam Container_tmpl `operator[]`, `size_type` */ template class Container_tmpl = std::vector> class segment_tree { static_assert(std::is_assignable() + std::declval())>::value, "\'Monoid\' has no proper binary \'operator+\'."); constexpr static bool __support_lazy = !std::is_void::value; #if __cplusplus < 201703L struct node_base { node_base() = default; node_base(Monoid const &__x) : __v(__x) {} operator bool() const { return __f; } void operator=(Monoid const &__x) { __v = __x; __f = true; } Monoid &operator*() { return __v; } Monoid const &operator*() const { return __v; } void reset() { __f = false; } private: Monoid __v{}; bool __f{true}; }; #else struct node_base : std::optional { using std::optional::operator=; node_base() : std::optional(Monoid{}) {} }; #endif struct node_lazy : node_base { using node_base::operator=; std::optional __z; }; using node = typename std::conditional<__support_lazy, node_lazy, node_base>::type; using container_type = Container_tmpl; public: using size_type = typename container_type::size_type; class iterator { segment_tree *__p; size_type __i; public: using difference_type = typename std::make_signed::type; using value_type = Monoid; using reference = Monoid &; using pointer = iterator; using iterator_category = std::random_access_iterator_tag; /** * @brief Construct a new iterator object * */ iterator() = default; /** * @brief Construct a new iterator object * * @param __p Pointer to a segment tree object * @param __i Index */ iterator(segment_tree *__p, size_type __i) : __p(__p), __i(__i) {} bool operator==(iterator const &rhs) const { return __p == rhs.__p && __i == rhs.__i; } bool operator!=(iterator const &rhs) const { return !operator==(rhs); } bool operator<(iterator const &rhs) const { return __i < rhs.__i; } bool operator>(iterator const &rhs) const { return __i > rhs.__i; } bool operator<=(iterator const &rhs) const { return __i <= rhs.__i; } bool operator>=(iterator const &rhs) const { return __i >= rhs.__i; } iterator &operator++() { return ++__i, *this; } iterator &operator--() { return --__i, *this; } difference_type operator-(iterator const &rhs) const { return __i - rhs.__i; } /** * @brief * * @return reference */ reference operator*() const { return __p->operator[](__i); } }; using value_type = typename iterator::value_type; using reference = typename iterator::reference; iterator begin() { return {this, 0}; } iterator end() { return {this, size_orig}; } auto rbegin() { return std::make_reverse_iterator(end()); } auto rend() { return std::make_reverse_iterator(begin()); } protected: size_type size_orig, height, size_ext; container_type data; node &pull(size_type __i) noexcept { if (!data[__i]) data[__i] = *pull(__i << 1) + *pull(__i << 1 | 1); return data[__i]; } void push(size_type __i) { if (auto &__lz = data[__i].__z) { apply(data[__i << 1], *__lz); apply(data[__i << 1 | 1], *__lz); __lz.reset(); } } void sync(size_type __i) { if (!data[__i]) data[__i] = *pull(__i << 1) + *pull(__i << 1 | 1); else if (data[__i].__z) { apply(data[__i << 1], *data[__i].__z); apply(data[__i << 1 | 1], *data[__i].__z); data[__i].__z.reset(); } } template void apply(node &__nd, _End const &endo) { *__nd = *__nd * endo; __nd.__z = __nd.__z ? *__nd.__z * endo : endo; } // template // void apply_top(size_t __i, _End const &endo) { // auto &__nd = pull(__i); // *__nd = *__nd * endo; // __nd.__z = __nd.__z ? *__nd.__z * endo : endo; // } template constexpr decltype(std::declval()(Monoid{})) pass_args( Pred pred, Monoid const &_1, [[maybe_unused]] size_type _2) { return pred(_1); } template constexpr decltype(std::declval()(Monoid{}, size_type{})) pass_args( Pred pred, Monoid const &_1, size_type _2) { return pred(_1, _2); } template size_type left_partition_subtree(size_type __i, Monoid mono, size_type step, Pred pred) { assert(__i); while (__i < size_ext) { if constexpr (__support_lazy) push(__i); const Monoid tmp = *pull((__i <<= 1) | 1) + mono; if (pass_args(pred, tmp, ((__i | 1) << --step) ^ size_ext)) mono = tmp; else ++__i; } return ++__i -= size_ext; } template size_type right_partition_subtree(size_type __i, Monoid mono, size_type step, Pred pred) { assert(__i); while (__i < size_ext) { if constexpr (__support_lazy) push(__i); const Monoid tmp = mono + *pull(__i <<= 1); if (pass_args(pred, tmp, ((__i | 1) << --step) ^ size_ext)) ++__i, mono = tmp; } return (__i -= size_ext) < size_orig ? __i : size_orig; } public: /** * @brief Construct a new segment tree object * * @param __n Number of elements. */ segment_tree(size_type __n = 0) : size_orig{__n}, height(__n > 1 ? 64 - __builtin_clzll(__n - 1) : 0), size_ext{size_type{1} << height} { if constexpr (std::is_constructible::value) data = container_type(size_ext << 1); data[0].reset(); } /** * @brief Construct a new segment tree object * * @param __n Number of elements. * @param init */ segment_tree(size_type __n, Monoid const &init) : segment_tree(__n) { for (auto i = begin(); i != end(); ++i) *i = init; } /** * @brief Construct a new segment tree object * * @tparam Tp * @param __n Number of elements. * @param init */ template ::value>::type * = nullptr> segment_tree(size_type __n, Tp &&init) : segment_tree(__n) { for (auto i = begin(); i != end(); ++i) *i = init; } /** * @brief Construct a new segment tree object * * @tparam Iterator * @param __first * @param __last */ template ::value_type, Monoid>::value> * = nullptr> segment_tree(Iterator __first, Iterator __last) : segment_tree(std::distance(__first, __last)) { for (auto i = begin(); __first != __last; ++i, ++__first) *i = *__first; } operator Container_tmpl() const { Container_tmpl __c(size()); for (size_type __i = 0; __i != size(); ++__i) __c[__i] = *data[__i | size_ext]; return __c; } /** * @return Number of elements. */ size_type size() const { return size_orig; } /** * @return Whether %segment_tree is empty. */ bool empty() const { return !size(); } /** * @param __i Index of the element * @return Reference to the element. */ reference operator[](size_type __i) { assert(__i < size_orig); reference __ref = *data[__i |= size_ext]; if constexpr (__support_lazy) { for (size_t __h{height}; __h; --__h) { push(__i >> __h); data[__i >> __h].reset(); } } else { while (data[__i >>= 1]) data[__i].reset(); } return __ref; } /** * @param first Left end, inclusive * @param last Right end, exclusive * @return Sum of elements in the interval. */ value_type fold(size_type first, size_type last) { assert(last <= size_orig); if (!(first < last)) return {}; first += size_ext, last += size_ext; value_type left{}, right{}; for (size_t l = first, r = last--; l != r; l >>= 1, r >>= 1) { if (l & 1) left = left + *pull(l++); if (r & 1) right = *pull(--r) + right; if constexpr (__support_lazy) { if (data[first >>= 1].__z) left = left * *data[first].__z; if (data[last >>= 1].__z) right = right * *data[last].__z; } } if constexpr (__support_lazy) { while (first >>= 1, last >>= 1) { if (data[first].__z) left = left * *data[first].__z; if (data[last].__z) right = right * *data[last].__z; } } // if (first >= last) return Monoid{}; // first += size_ext, last += size_ext - 1; // Monoid left{}, right{}; // for (size_t l = first, r = last + 1; last; l >>= 1, r >>= 1) { // if (l < r) { // if (l & 1) left = left + data[l++]; // if (r & 1) right = data[--r] + right; // } // if (first >>= 1, last >>= 1) { // left = left * lazy[first]; // right = right * lazy[last]; // } // } // return left + right; return left + right; } /** * @return The whole sum. */ value_type fold() { return fold(0, size_orig); } template void update(size_type first, size_type last, _End const &endo) { static_assert(__support_lazy); assert(last <= size_orig); if (!(first < last)) return; first += size_ext, last += size_ext; --last; for (auto i = height; i; --i) push(first >> i), push(last >> i); ++last; for (auto l = first, r = last; l < r; l >>= 1, r >>= 1) { if (l & 1) apply(pull(l++), endo); if (r & 1) apply(pull(--r), endo); } for (first >>= __builtin_ffs(first); data[first]; first >>= 1) data[first].reset(); for (last >>= __builtin_ffs(last); data[last]; last >>= 1) data[last].reset(); } /** * @brief Binary search for the partition point. * @param right Right fixed end of the interval, exclusive * @param pred Predicate in the form of either 'bool(Monoid)' or 'bool(Monoid, * size_type)' * @return Left end of the extremal interval satisfying the condition, * inclusive. */ template size_type left_partition(size_type right, Pred pred) { assert(right <= size_orig); right += size_ext; if constexpr (__support_lazy) for (size_t i{height}; i; --i) push(right >> i); Monoid mono{}; for (size_type left{size_ext}, step{}; left != right; left >>= 1, right >>= 1, ++step) { if ((left & 1) != (right & 1)) { Monoid tmp = *pull(--right) + mono; if (!pass_args(pred, tmp, (right << step) ^ size_ext)) return left_partition_subtree(right, mono, step, pred); mono = tmp; } } return 0; } /** * @brief Binary search for the partition point. * @param left Left fixed end of the interval, inclusive * @param pred Predicate in the form of either 'bool(Monoid)' or 'bool(Monoid, * size_type)' * @return Right end of the extremal interval satisfying the condition, * exclusive. */ template size_type right_partition(size_type left, Pred pred) { assert(left <= size_orig); left += size_ext; if constexpr (__support_lazy) for (size_t i{height}; i; --i) push(left >> i); Monoid mono{}; for (size_type right{size_ext << 1}, step{}; left != right; left >>= 1, right >>= 1, ++step) { if ((left & 1) != (right & 1)) { Monoid tmp = mono + *pull(left); if (!pass_args(pred, tmp, ((left + 1) << step) ^ size_ext)) return right_partition_subtree(left, mono, step, pred); mono = tmp; ++left; } } return size_orig; } }; } // namespace workspace #line 2 "Library/src/modular/modint.hpp" /** * @file modint.hpp * * @brief Modular Arithmetic */ #line 12 "Library/src/modular/modint.hpp" #line 2 "Library/src/utils/sfinae.hpp" /** * @file sfinae.hpp * @brief SFINAE */ #line 10 "Library/src/utils/sfinae.hpp" #include #ifndef __INT128_DEFINED__ #ifdef __SIZEOF_INT128__ #define __INT128_DEFINED__ 1 #else #define __INT128_DEFINED__ 0 #endif #endif namespace std { #if __INT128_DEFINED__ template <> struct make_signed<__uint128_t> { using type = __int128_t; }; template <> struct make_signed<__int128_t> { using type = __int128_t; }; template <> struct make_unsigned<__uint128_t> { using type = __uint128_t; }; template <> struct make_unsigned<__int128_t> { using type = __uint128_t; }; #endif } // namespace std namespace workspace { template struct variadic_front { using type = Tp; }; template struct variadic_back; template struct variadic_back { using type = Tp; }; template struct variadic_back { using type = typename variadic_back::type; }; template class trait> using enable_if_trait_type = typename std::enable_if::value>::type; template using element_type = typename std::decay()))>::type; template struct has_begin : std::false_type {}; template struct has_begin()), nullptr)> : std::true_type {}; template struct mapped_of { using type = element_type; }; template struct mapped_of::first_type> { using type = typename T::mapped_type; }; template using mapped_type = typename mapped_of::type; template struct is_integral_ext : std::false_type {}; template struct is_integral_ext< T, typename std::enable_if::value>::type> : std::true_type {}; #if __INT128_DEFINED__ template <> struct is_integral_ext<__int128_t> : std::true_type {}; template <> struct is_integral_ext<__uint128_t> : std::true_type {}; #endif #if __cplusplus >= 201402 template constexpr static bool is_integral_ext_v = is_integral_ext::value; #endif template struct multiplicable_uint { using type = uint_least32_t; }; template struct multiplicable_uint< T, typename std::enable_if<(2 < sizeof(T)) && (!__INT128_DEFINED__ || sizeof(T) <= 4)>::type> { using type = uint_least64_t; }; #if __INT128_DEFINED__ template struct multiplicable_uint::type> { using type = __uint128_t; }; #endif template struct multiplicable_int { using type = typename std::make_signed::type>::type; }; } // namespace workspace #line 14 "Library/src/modular/modint.hpp" namespace workspace { namespace internal { /** * @brief Base of modular arithmetic. * * @tparam Mod identifier, which represents modulus if positive * @tparam Storage Reserved size for inverse calculation */ template struct modint_base { static_assert(is_integral_ext::value, "Mod must be integral type."); using mod_type = typename std::make_signed::type, decltype(Mod)>::type>::type; using value_type = typename std::decay::type; using mul_type = typename multiplicable_uint::type; static mod_type mod; static value_type storage; constexpr static void reserve(unsigned __n) noexcept { storage = __n; } protected: value_type value = 0; public: constexpr modint_base() noexcept = default; template ::value>::type * = nullptr> constexpr modint_base(int_type n) noexcept : value((n %= mod) < 0 ? n += mod : n) {} constexpr modint_base(bool n) noexcept : value(n) {} constexpr operator value_type() const noexcept { return value; } constexpr static modint_base one() noexcept { return 1; } // unary operators {{ constexpr modint_base operator++(int) noexcept { modint_base __t{*this}; operator++(); return __t; } constexpr modint_base operator--(int) noexcept { modint_base __t{*this}; operator--(); return __t; } constexpr modint_base &operator++() noexcept { if (++value == mod) value = 0; return *this; } constexpr modint_base &operator--() noexcept { if (!value) value = mod; --value; return *this; } constexpr modint_base operator-() const noexcept { modint_base __t; __t.value = value ? mod - value : 0; return __t; } // }} unary operators // operator+= {{ constexpr modint_base &operator+=(modint_base const &rhs) noexcept { if ((value += rhs.value) >= mod) value -= mod; return *this; } template constexpr typename std::enable_if::value, modint_base>::type & operator+=(int_type const &rhs) noexcept { if (((value += rhs) %= mod) < 0) value += mod; return *this; } // }} operator+= // operator+ {{ template constexpr typename std::enable_if::value, modint_base>::type operator+(int_type const &rhs) const noexcept { return modint_base{*this} += rhs; } constexpr modint_base operator+(modint_base rhs) const noexcept { return rhs += *this; } template constexpr friend typename std::enable_if::value, modint_base>::type operator+(int_type const &lhs, modint_base rhs) noexcept { return rhs += lhs; } // }} operator+ // operator-= {{ constexpr modint_base &operator-=(modint_base const &rhs) noexcept { if ((value -= rhs.value) < 0) value += mod; return *this; } template constexpr typename std::enable_if::value, modint_base>::type & operator-=(int_type rhs) noexcept { if (((value -= rhs) %= mod) < 0) value += mod; return *this; } // }} operator-= // operator- {{ template constexpr typename std::enable_if::value, modint_base>::type operator-(int_type const &rhs) const noexcept { return modint_base{*this} -= rhs; } constexpr modint_base operator-(modint_base const &rhs) const noexcept { modint_base __t; if (((__t.value = value) -= rhs.value) < 0) __t.value += mod; return __t; } template constexpr friend typename std::enable_if::value, modint_base>::type operator-(int_type lhs, modint_base const &rhs) noexcept { if (((lhs -= rhs.value) %= mod) < 0) lhs += mod; modint_base __t; __t.value = lhs; return __t; } // }} operator- // operator*= {{ constexpr modint_base &operator*=(modint_base const &rhs) noexcept { if (!rhs.value) value = 0; else if (value) { mul_type __r(value); value = static_cast((__r *= rhs.value) %= mod); } return *this; } template constexpr typename std::enable_if::value, modint_base>::type & operator*=(int_type rhs) noexcept { if (!rhs) value = 0; else if (value) { if ((rhs %= mod) < 0) rhs += mod; mul_type __r(value); value = static_cast((__r *= rhs) %= mod); } return *this; } // }} operator*= // operator* {{ constexpr modint_base operator*(modint_base const &rhs) const noexcept { if (!value or !rhs.value) return {}; mul_type __r(value); modint_base __t; __t.value = static_cast((__r *= rhs.value) %= mod); return __t; } template constexpr typename std::enable_if::value, modint_base>::type operator*(int_type rhs) const noexcept { if (!value or !rhs) return {}; if ((rhs %= mod) < 0) rhs += mod; mul_type __r(value); modint_base __t; __t.value = static_cast((__r *= rhs) %= mod); return __t; } template constexpr friend typename std::enable_if::value, modint_base>::type operator*(int_type lhs, modint_base const &rhs) noexcept { if (!lhs or !rhs.value) return {}; if ((lhs %= mod) < 0) lhs += mod; mul_type __r(lhs); modint_base __t; __t.value = static_cast((__r *= rhs.value) %= mod); return __t; } // }} operator* protected: static value_type _mem(value_type __x) { static std::vector __m{0, 1}; static value_type __i = (__m.reserve(Storage), 1); while (__i < __x) { ++__i; __m.emplace_back(mod - mul_type(mod / __i) * __m[mod % __i] % mod); } return __m[__x]; } template constexpr static typename std::enable_if::value, value_type>::type _div(mul_type __r, int_type __x) noexcept { assert(__x); if (!__r) return 0; int_type __v{}; bool __neg = __x < 0 ? __x = -__x, true : false; if (__x < storage) __v = _mem(__x); else { int_type __y{mod}, __u{1}, __t; while (__x) __t = __y / __x, __y ^= __x ^= (__y -= __t * __x) ^= __x, __v ^= __u ^= (__v -= __t * __u) ^= __u; if (__y < 0) __neg ^= 1; } if (__neg) __v = 0 < __v ? mod - __v : -__v; else if (__v < 0) __v += mod; if (__r == 1) return static_cast(__v); return static_cast((__r *= __v) %= mod); } public: // operator/= {{ constexpr modint_base &operator/=(modint_base const &rhs) noexcept { if (value) value = _div(value, rhs.value); return *this; } template constexpr typename std::enable_if::value, modint_base>::type & operator/=(int_type rhs) noexcept { if (value) value = _div(value, rhs %= mod); return *this; } // }} operator/= // operator/ {{ constexpr modint_base operator/(modint_base const &rhs) const noexcept { if (!value) return {}; modint_base __t; __t.value = _div(value, rhs.value); return __t; } template constexpr typename std::enable_if::value, modint_base>::type operator/(int_type rhs) const noexcept { if (!value) return {}; modint_base __t; __t.value = _div(value, rhs %= mod); return __t; } template constexpr friend typename std::enable_if::value, modint_base>::type operator/(int_type lhs, modint_base const &rhs) noexcept { if (!lhs) return {}; if ((lhs %= mod) < 0) lhs += mod; modint_base __t; __t.value = _div(lhs, rhs.value); return __t; } // }} operator/ constexpr modint_base inv() const noexcept { return _div(1, value); } template friend constexpr typename std::enable_if::value, modint_base>::type pow(modint_base b, int_type e) noexcept { if (e < 0) { e = -e; b.value = _div(1, b.value); } modint_base __r; for (__r.value = 1; e; e >>= 1, b *= b) if (e & 1) __r *= b; return __r; } template constexpr typename std::enable_if::value, modint_base>::type pow(int_type e) const noexcept { modint_base __r, b; __r.value = 1; for (b.value = e < 0 ? e = -e, _div(1, value) : value; e; e >>= 1, b *= b) if (e & 1) __r *= b; return __r; } friend std::ostream &operator<<(std::ostream &os, const modint_base &rhs) noexcept { return os << rhs.value; } friend std::istream &operator>>(std::istream &is, modint_base &rhs) noexcept { intmax_t value; rhs = (is >> value, value); return is; } }; template typename modint_base::mod_type modint_base::mod = Mod > 0 ? Mod : 0; template typename modint_base::value_type modint_base::storage = Storage; } // namespace internal /** * @brief Modular arithmetic. * * @tparam Mod modulus * @tparam Storage Reserved size for inverse calculation */ template 0)>::type * = nullptr> using modint = internal::modint_base; /** * @brief Runtime modular arithmetic. * * @tparam type_id uniquely assigned * @tparam Storage Reserved size for inverse calculation */ template using modint_runtime = internal::modint_base<-(signed)type_id, Storage>; // #define modint_newtype modint_runtime<__COUNTER__> } // namespace workspace #line 29 "other/ms.cc" namespace workspace { using mint = modint<(int)1e9 + 7>; using mat = matrix; using vec = matrix; void main() { // start here! using std::cin; using std::cout; int n, q; cin >> n >> q; segment_tree sgt(n); // init { mint a = 0, b = 1; for (auto &&x : sgt) { x = {{0, 1, a}}; std::swap(b, a += b); } } while (q--) { int tp, l, r, k; cin >> tp >> l >> r >> k; ++r; mat op = mat::eye(); switch (tp) { case 0: { cout << sgt.fold(l, r)[0][0] * k << "\n"; } break; case 1: { op[0][0] = 0; op[1][0] = k; sgt.update(l, r, op); } break; case 2: { op[1][0] = k; sgt.update(l, r, op); } break; case 3: { op[0][0] = k; sgt.update(l, r, op); } break; case 4: { op[2][0] = k; sgt.update(l, r, op); } break; } } } } // namespace workspace int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); workspace::main(); }