#include template using vc = std::vector; struct CustomHash { static constexpr uint64_t splitmix64(uint64_t x) { x += 0x9e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31); } static constexpr size_t append(size_t x, size_t y) { return x ^ (y >> 1) ^ ((y & 1) << (sizeof(size_t) * 8 - 1)); } size_t operator()(uint64_t x) const { static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } template size_t operator()(std::pair const &p) const { return append((*this)(p.first), (*this)(p.second)); } template size_t operator()(std::tuple const &tp) const { size_t ret = 0; std::apply( [&](Ts const &...targs) { ((ret = append(ret, (*this)(targs))), ...); }, tp); return ret; } template < class Tp, std::enable_if_t().begin()), typename Tp::iterator>::value && std::is_same().end()), typename Tp::iterator>::value> * = nullptr> size_t operator()(Tp const &tp) const { size_t ret = 0; for (auto &&i : tp) ret = append(ret, (*this)(i)); return ret; } }; using u32 = uint32_t; #define for_(i, l, r, vars...) \ for (std::make_signed_t i = (l), i##end = (r), ##vars; \ i <= i##end; \ ++i) #define rfor_(i, r, l, vars...) \ for (std::make_signed_t i = (r), i##end = (l), ##vars; \ i >= i##end; \ --i) template constexpr auto chkmin(Tp &a, Tp b) -> bool { return b < a ? a = b, true : false; } template constexpr auto chkmax(Tp &a, Tp b) -> bool { return a < b ? a = b, true : false; } template constexpr auto ispow2(Tp i) -> bool { return i && (i & -i) == i; } #define TPL_SIZE_(Tuple) std::tuple_size_v> namespace tuple_detail_ { template constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence) { return std::make_tuple(std::get(t)...); } template constexpr auto apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence) { return std::make_tuple( std::forward(f)(std::get(lhs), std::get(rhs))...); } } // namespace tuple_detail_ template constexpr auto subtuple(Tuple &&t) { static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) && Begin + Len <= TPL_SIZE_(Tuple), "Out of range"); return tuple_detail_::subtuple_impl_(t, std::make_index_sequence()); } template constexpr auto tuple_push(Tp &&v, Tuple &&t) { static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple"); return std::tuple_cat(subtuple<0, Pos>(t), std::make_tuple(v), subtuple(t)); } template constexpr auto tuple_push_front(Tp &&v, Tuple &&t) { return tuple_push<0>(v, t); } template constexpr auto tuple_push_back(Tp &&v, Tuple &&t) { return tuple_push(v, t); } template constexpr auto tuple_pop(Tuple &&t) { static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple"); return std::tuple_cat(subtuple<0, Pos>(t), subtuple(t)); } template constexpr auto tuple_pop_front(Tuple &&t) { return tuple_pop<0>(t); } template constexpr auto tuple_pop_back(Tuple &&t) { return tuple_pop(t); } template constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) { return tuple_detail_::apply2_impl_( f, lhs, rhs, std::make_index_sequence()); } #define OO_PTEQ_(op) \ template \ constexpr auto operator op(std::pair lhs, \ const std::pair &rhs) { \ return std::pair{lhs.first op rhs.first, \ lhs.second op rhs.second}; \ } \ template \ constexpr auto operator op(std::tuple const &lhs, \ std::tuple const &rhs) { \ return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \ } \ template \ constexpr std::pair &operator op##=(std::pair &lhs, \ const std::pair &rhs) { \ lhs.first op## = rhs.first; \ lhs.second op## = rhs.second; \ return lhs; \ } \ template \ constexpr auto operator op##=(std::tuple &lhs, \ const std::tuple &rhs) { \ return lhs = lhs op rhs; \ } OO_PTEQ_(+) OO_PTEQ_(-) OO_PTEQ_(*) OO_PTEQ_(/) OO_PTEQ_(%) OO_PTEQ_(&) OO_PTEQ_(|) OO_PTEQ_(^) OO_PTEQ_(<<) OO_PTEQ_(>>) #undef OO_PTEQ_ #undef TPL_SIZE_ template std::istream &operator>>(std::istream &is, std::pair &p) { return is >> p.first >> p.second; } template std::ostream &operator<<(std::ostream &os, const std::pair &p) { return os << p.first << ' ' << p.second; } template std::istream &operator>>(std::istream &is, std::tuple &p) { std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p); return is; } template std::ostream &operator<<(std::ostream &os, const std::tuple &p) { std::apply( [&](Ts const &...targs) { std::size_t n{0}; ((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...); }, p); return os; } template < class Ch, class Tr, class Ct, std::enable_if_t().begin()), typename Ct::iterator>::value && std::is_same().end()), typename Ct::iterator>::value> * = nullptr> std::basic_ostream &operator<<(std::basic_ostream &os, const Ct &x) { if (x.begin() == x.end()) return os; for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' '; os << x.back(); return os; } using namespace std; namespace MODINT { constexpr int64_t safe_mod(int64_t x, int64_t m) { return (x %= m) < 0 ? x + m : x; } constexpr std::pair invgcd(int64_t a, int64_t b) { if ((a = safe_mod(a, b)) == 0) return {b, 0}; int64_t s = b, m0 = 0; for (int64_t q = 0, _ = 0, m1 = 1; a;) { _ = s - a * (q = s / a); s = a; a = _; _ = m0 - m1 * q; m0 = m1; m1 = _; } return {s, m0 + (m0 < 0 ? b / s : 0)}; } struct Barrett_ { uint32_t m_; uint64_t im; constexpr explicit Barrett_(uint32_t m = 998244353) : m_(m), im((uint64_t)(-1) / m + 1) {} constexpr uint32_t umod() const { return m_; } constexpr uint32_t mul(uint32_t a, uint32_t b) const { uint64_t z = a; z *= b; uint64_t x = (uint64_t)(((__uint128_t)z * im) >> 64); uint32_t v = (uint32_t)(z - x * m_); return v + (m_ <= v ? m_ : 0); } } bt_; template class DyMint { using self = DyMint; protected: uint32_t v_; public: static constexpr uint32_t mod() { return bt_.umod(); } static constexpr void set_mod(uint32_t m) { assert(1 <= m); bt_ = Barrett_(m); } static constexpr self raw(uint32_t v) { self x; x.v_ = v; return x; } constexpr DyMint(): v_(0) {} template ::value && std::is_signed::value> * = nullptr> constexpr DyMint(T v): DyMint() { int64_t x = (int64_t)(v % (int64_t)mod()); v_ = (uint32_t)(x + (x < 0 ? mod() : 0)); } template ::value && std::is_unsigned::value> * = nullptr> constexpr DyMint(T v): v_((uint32_t)(v % mod())) {} friend std::istream &operator>>(std::istream &is, self &x) { int64_t xx; is >> xx; xx %= mod(); x.v_ = (uint32_t)(xx + (xx < 0 ? mod() : 0)); return is; } friend std::ostream &operator<<(std::ostream &os, const self &x) { return os << x.v_; } constexpr const uint32_t &val() const { return v_; } constexpr explicit operator uint32_t() const { return val(); } constexpr uint32_t &data() { return v_; } constexpr self &operator++() { if (++v_ == mod()) v_ = 0; return *this; } constexpr self &operator--() { if (!v_) v_ = mod(); --v_; return *this; } constexpr self operator++(int) { self result = *this; ++*this; return result; } constexpr self operator--(int) { self result = *this; --*this; return result; } constexpr self &operator+=(const self &rhs) { v_ += rhs.v_; if (v_ >= mod()) v_ -= mod(); return *this; } constexpr self &operator-=(const self &rhs) { v_ -= rhs.v_; if (v_ >= mod()) v_ += mod(); return *this; } constexpr self &operator*=(const self &rhs) { v_ = bt_.mul(v_, rhs.v_); return *this; } constexpr self &operator/=(const self &rhs) { return *this = *this * inverse(rhs); } constexpr self operator+() const { return *this; } constexpr self operator-() const { return self() - *this; } constexpr friend self pow(self x, uint64_t y) { self res(1); for (; y; y >>= 1, x *= x) if (y & 1) res *= x; return res; } constexpr friend self inverse(const self &x) { auto &&_ = invgcd(x.v_, self::mod()); if (_.first != 1) throw std::runtime_error("Inverse not exist"); return _.second; } constexpr friend self operator+(self lhs, const self &rhs) { return lhs += rhs; } constexpr friend self operator-(self lhs, const self &rhs) { return lhs -= rhs; } constexpr friend self operator*(self lhs, const self &rhs) { return lhs *= rhs; } constexpr friend self operator/(self lhs, const self &rhs) { return lhs /= rhs; } constexpr friend bool operator==(const self &lhs, const self &rhs) { return lhs.v_ == rhs.v_; } constexpr friend bool operator!=(const self &lhs, const self &rhs) { return lhs.v_ != rhs.v_; } }; } // namespace MODINT using MODINT::DyMint; using dmint = DyMint<>; auto solve([[maybe_unused]] int t_ = 0) -> void { u32 n, mod; cin >> n >> mod; dmint::set_mod(mod); vc fact(n * 3 + 1), inv_fact(n * 3 + 1); fact[0] = 1; for_(i, 1, n * 3) fact[i] = fact[i - 1] * i; inv_fact[n * 3] = 1 / fact[n * 3]; rfor_(i, n * 3, 1) inv_fact[i - 1] = inv_fact[i] * i; dmint ans = 0; ans += fact[n * 3] * 3; ans -= fact[n * 2] * inv_fact[n] * fact[n * 2] * 2; for_(i, 0, n) { auto _ = fact[n] * inv_fact[i] * inv_fact[n - i] * fact[n]; ans += _ * _ * fact[n * 2 - i] * inv_fact[n - i]; } ans -= fact[n * 2] * 2 - fact[n]; ans -= 1; cout << ans.data(); } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int i_ = 0; solve(i_); return 0; }