Submission #74370337


Source Code Expand

// C++14

#ifndef use_int128
# define use_int128 1
#endif

#include <cstdint>
#include <type_traits>
#include <limits>
#include <iterator>
#include <numeric>
#include <functional>
#include <iostream>
#include <algorithm>

#define expect(cond) __builtin_expect(static_cast<bool>(cond), true)
#define unexpect(cond) __builtin_expect(static_cast<bool>(cond), false)

namespace modint_nm {

    using u32 = std::uint32_t;
    using u64 = std::uint64_t;
    using umx = std::uintmax_t;
    using i32 = std::int32_t;
    using imx = std::intmax_t;

    // for primitive root
    constexpr u32 phi(u32 n) noexcept {
        u32 ph = n;
        for (u32 i = 2; u64(i) * i <= n; ++i)if (n % i == 0u){ph = ph / i * (i - 1);while (n % i == 0u)n /= i;}
        return n > 1? ph / n * (n - 1) : ph;
    }
    constexpr bool is_prime(u32 v) noexcept {
        if (v <= 1)return 0;
        for (u32 i = 2; u64(i) * i <= v; ++i)if (v % i == 0)return 0;
        return 1;
    }

    template <u32 mod, typename type, typename = void> struct modval_t;
    template <u32 mod, typename type> struct modval_t <mod, type, std::enable_if_t<std::is_unsigned<type>::value> >
        { static constexpr u32 modval(type v) noexcept { return v % mod; } };
    template <u32 mod, typename type> struct modval_t <mod, type, std::enable_if_t<std::is_signed<type>::value> >
        { static constexpr u32 modval(type v) noexcept { v %= i32(mod);return v < 0? v + mod : v; } };
    template <u32 mod, typename type> struct modval_t <mod, type, std::enable_if_t<std::is_floating_point<type>::value> >
        { static constexpr u32 modval(type v) noexcept { return modval_t<mod, imx>::modval(imx(v)); } };
    #if use_int128
    template <u32 mod> struct modval_t <mod, __int128_t>
        { static constexpr u32 modval(__int128_t v) noexcept { v %= i32(mod);return v < 0? v + mod : v; } };
    template <u32 mod> struct modval_t <mod, __uint128_t>
        { static constexpr u32 modval(__uint128_t v) noexcept { return v % mod; } };
    #endif

    template <u32 mod> constexpr auto modsplus(u32 &a, u32 b) noexcept
        -> std::enable_if_t<(std::numeric_limits<u32>::max() / 2 + 1 < mod), void> { if (a >= mod - b)a -= mod - b;else a += b; }
    template <u32 mod> constexpr auto modsplus(u32 &a, u32 b) noexcept
        -> std::enable_if_t<std::numeric_limits<u32>::max() / 2 + 1 >= mod, void> { a += b;if (a >= mod)a -= mod; }
    template <u32 mod> constexpr auto modplus(u32 a, u32 b) noexcept
        -> std::enable_if_t<(std::numeric_limits<u32>::max() / 2 + 1 < mod), u32> { return a >= mod - b? a - (mod - b) : a + b; }
    template <u32 mod> constexpr auto modplus(u32 a, u32 b) noexcept
        -> std::enable_if_t<std::numeric_limits<u32>::max() / 2 + 1 >= mod, u32> { a += b;return a >= mod? a - mod : a; }

    template <u32 mod> constexpr void modssubt(u32 &a, u32 b) noexcept { if (a < b)a += mod - b; else a -= b; }
    template <u32 mod> constexpr u32 modsubt(u32 a, u32 b) noexcept { return a < b? a + (mod - b) : a - b; }

    template <u32 mod> constexpr auto modmult(u32 a, u32 b) noexcept
        -> std::enable_if_t<(u64(mod - 1) * (mod - 1) <= u32(-1)), u32> { return a * b % mod; }
    template <u32 mod> constexpr auto modmult(u32 a, u32 b) noexcept
        -> std::enable_if_t<(u64(mod - 1) * (mod - 1) > u32(-1)), u32> { return u64(a) * b % mod; }
    template <u32 mod> constexpr void modsmult(u32 &a, u32 b) noexcept { a = modmult<mod>(a, b); }

    template <u32 mod> constexpr u32 modfpow(u32 a, umx b) noexcept
        { u32 ret = 1;for (; b; b >>= 1, a = modmult<mod>(a, a))if (b & 1)ret = modmult<mod>(ret, a);return ret; }
    template <u32 mod> constexpr void modsfpow(u32 &a, umx b) noexcept { a = modfpow<mod>(a, b); }

    // 假定值在模范围内,减少一次取模操作
    struct in_mod_range_t { };
    constexpr in_mod_range_t in_mod_range {};

    struct modint_tag { };

    template <u32> struct modint;

    template <u32 mod_>
        struct modint {
            typedef modint_tag is_modint_t;
            static constexpr u32 mod = mod_;
            static constexpr bool mod_is_prime = is_prime(mod);
            u32 val;
            constexpr modint() noexcept : val() { }
            template <typename Val_t, typename = decltype(modval_t<mod, Val_t>::modval(std::declval<Val_t>())) >
                constexpr modint(Val_t Val) noexcept : val(modval_t<mod, Val_t>::modval(Val)) {}
            constexpr modint(const modint &) noexcept = default;
            constexpr modint(modint &&) noexcept = default;
            constexpr modint(in_mod_range_t, u32 v) noexcept : val{v} {}
            template <typename Val_t> constexpr modint &operator = (Val_t Val) noexcept
                { val = modval_t<mod, Val_t>::modval(Val);return *this; }
            constexpr modint &operator = (const modint &) noexcept = default;
            constexpr modint &operator = (modint &&) noexcept = default;
            constexpr modint &operator += (modint o) noexcept { modsplus<mod>(val, o.val);return *this; }
            constexpr modint &operator -= (modint o) noexcept { modssubt<mod>(val, o.val);return *this; }
            constexpr modint &operator *= (modint o) noexcept { modsmult<mod>(val, o.val);return *this; }
            constexpr modint &operator ++ () noexcept {if (unexpect(++val == mod))val = 0;return *this;}
            constexpr modint operator ++ (int) noexcept {modint R = *this;if (unexpect(++val == mod))val = 0;return R;}
            constexpr modint &operator -- () noexcept {if (unexpect(--val == u32(-1)))val = mod - 1;return *this;}
            constexpr modint operator -- (int) noexcept {modint R = *this;if (unexpect(--val == u32(-1)))val = mod - 1;return R;}
            constexpr modint operator - () const noexcept { return modint(in_mod_range, val? mod - val : 0u); }
            constexpr modint inv() const noexcept { return pow(*this, phi_mod - 1); }
            constexpr modint &operator /= (modint o) noexcept { modsmult<mod>(val, o.inv().val);return *this; }
            constexpr u32 value() const noexcept { return val; }
            explicit constexpr operator u32 () const noexcept { return val; }
            template <typename _Tp> constexpr operator _Tp () const noexcept { return (_Tp)val; }

            constexpr modint& plussubt(bool v, modint x) noexcept //+=(-1)^v*x
                { if (v)*this -= x; else *this += x; return *this; }
            template <typename _Tp, typename = std::enable_if_t<std::is_integral<_Tp>::value> >
                constexpr modint& plussubt(_Tp v, modint x) noexcept //+=(-1)^v*x
                    { if (v & 1)*this -= x; else *this += x; return *this; }

            static constexpr modint nan = modint(in_mod_range, mod);

            static constexpr u32 phi_mod = phi(mod);

        }; // __is_trivially_copyable(modint<...>) = true

    template <u32 mod>
        constexpr u32 modint<mod>::mod;
    template <u32 mod>
        constexpr modint<mod> modint<mod>::nan;
    template <u32 mod>
        constexpr bool modint<mod>::mod_is_prime;
    template <u32 mod>
        constexpr u32 modint<mod>::phi_mod;

    template <typename...> using __void_t = void;
    template <u32 mod, typename type> struct modval_t <mod, type,
            __void_t<std::enable_if_t<!std::is_arithmetic<type>::value>, decltype(type::operator modint<mod>()) > >
        { static constexpr u32 modval(type v) noexcept { return ((modint<mod>)v).value(); } };

    template <u32 mod> constexpr modint<mod> operator + (modint<mod> a, modint<mod> b) noexcept
        { return modint<mod>(in_mod_range, modplus<mod>(a.val, b.val)); }
    template <u32 mod, typename _T> constexpr modint<mod> operator + (_T a, modint<mod> b) noexcept { return modint<mod>(a) + b; }
    template <u32 mod, typename _T> constexpr modint<mod> operator + (modint<mod> a, _T b) noexcept { return a + modint<mod>(b); }

    template <u32 mod> constexpr modint<mod> operator - (modint<mod> a, modint<mod> b) noexcept
        { return modint<mod>(in_mod_range, modsubt<mod>(a.val, b.val)); }
    template <u32 mod, typename _T> constexpr modint<mod> operator - (_T a, modint<mod> b) noexcept { return modint<mod>(a) - b; }
    template <u32 mod, typename _T> constexpr modint<mod> operator - (modint<mod> a, _T b) noexcept { return a - modint<mod>(b); }

    template <u32 mod> constexpr modint<mod> operator * (modint<mod> a, modint<mod> b) noexcept
        { return modint<mod>(in_mod_range, modmult<mod>(a.val, b.val)); }
    template <u32 mod, typename _T> constexpr modint<mod> operator * (_T a, modint<mod> b) noexcept { return modint<mod>(a) * b; }
    template <u32 mod, typename _T> constexpr modint<mod> operator * (modint<mod> a, _T b) noexcept { return a * modint<mod>(b); }

    template <u32 mod> constexpr modint<mod> operator / (modint<mod> a, modint<mod> b) noexcept
        { return modint<mod>(in_mod_range, modmult<mod>(a.val, b.inv().val)); }
    template <u32 mod, typename _T> constexpr modint<mod> operator / (_T a, modint<mod> b) noexcept { return modint<mod>(a) / b; }
    template <u32 mod, typename _T> constexpr modint<mod> operator / (modint<mod> a, _T b) noexcept { return a / modint<mod>(b); }

    template <typename _Tp, typename = void> struct is_modint : std::false_type { };
    template <typename _Tp> struct is_modint <_Tp, typename _Tp::is_modint_t> : std::true_type { };

    namespace __modint_help {

        template <typename _T>
            constexpr auto __safe_l(_T a, u32 b) noexcept -> std::enable_if_t<std::is_unsigned<_T>::value, bool> {
                return a < b;
            }
        template <typename _T>
            constexpr auto __safe_l(_T a, u32 b) noexcept -> std::enable_if_t<std::is_signed<_T>::value, bool> {
                return a < _T(0)? true : std::make_unsigned_t<_T>(a) < b;
            }
        #if use_int128
        constexpr bool __safe_l(__uint128_t a, u32 b){
            return a < b;
        }
        constexpr bool __safe_l(__int128_t a, u32 b){
            return a < 0? true : __uint128_t(a) < b;
        }
        #endif

    }

    template <u32 mod, typename _T>
        constexpr std::enable_if_t<(mod > 2 && is_prime(mod)) &&
                std::is_convertible<_T, modint<mod - 1> >::value, modint<mod> >
            pow(modint<mod> a, _T b) noexcept
                { return modint<mod>(in_mod_range, modfpow<mod>(a.val, modint<mod - 1>(b).value())); }
    template <u32 mod, typename _T>
        constexpr std::enable_if_t<!(mod > 2 && is_prime(mod)) && std::is_unsigned<_T>::value, modint<mod> >
            pow(modint<mod> a, _T b) noexcept
                { constexpr u32 p = phi(mod); return modint<mod>(in_mod_range, modfpow<mod>(a.val, __modint_help::__safe_l(b, p)? b : b % p + p)); }
    template <u32 mod, typename _T>
        constexpr std::enable_if_t<!(mod > 2 && is_prime(mod)) && std::is_signed<_T>::value, modint<mod> >
            pow(modint<mod> a, _T b) noexcept {
                constexpr u32 p = phi(mod);
                if (b >= 0)return modint<mod>(in_mod_range, modfpow<mod>(a.val, __modint_help::__safe_l(b, p)? b : b % p + p));
                b = -b;
                umx T = umx(__modint_help::__safe_l(b, p)? b : b % p + p) * (p - 1);
                return modint<mod>(in_mod_range, modfpow<mod>(a.val, T < p? T : T % p + p));
            }

    template <u32 mod> constexpr modint<mod> fma(modint<mod> a, modint<mod> b, modint<mod> c) noexcept
        { return modint<mod>(in_mod_range, (u64(a.val) * b.val + c.val) % mod); }
    template <u32 mod> constexpr modint<mod> fma(modint<mod> a, modint<mod> b, u32 c) noexcept
        { return modint<mod>(in_mod_range, (u64(a.val) * b.val + c) % mod); }
    template <u32 mod> constexpr modint<mod> fma(in_mod_range_t, modint<mod> a, modint<mod> b, u64 c) noexcept //assume c + (mod-1)^2 < u64 max
        { return modint<mod>(in_mod_range, (u64(a.val) * b.val + c) % mod); }

    template <u32 mod> constexpr modint<mod> fmam(modint<mod> a, modint<mod> b, modint<mod> c, modint<mod> d) noexcept
        { return modint<mod>(in_mod_range, (u64(a.val) * b.val + u64(c.val) * d.val) % mod); }

    template <u32 mod> constexpr modint<mod> fms(modint<mod> a, modint<mod> b, modint<mod> c) noexcept
        { return modint<mod>(in_mod_range, (u64(a.val) * b.val + mod - c.val) % mod); }

    template <u32 mod> constexpr modint<mod> fmsm(modint<mod> a, modint<mod> b, modint<mod> c, modint<mod> d) noexcept
        { constexpr u64 mm = u64(mod) * mod;return modint<mod>(in_mod_range, (u64(a.val) * b.val + mm - u64(c.val) * d.val) % mod); }

    template <u32 mod> // a += b * c
        constexpr void splusmult(modint<mod> &a, modint<mod> b, modint<mod> c) noexcept { a = fma(b, c, a); }

    template <u32 mod> struct modint_partial_order
        { constexpr bool operator () (modint<mod> a, modint<mod> b) const noexcept { return a.val < b.val; } };// 偏序关系

    template <u32 mod> constexpr bool operator == (modint<mod> a, modint<mod> b) noexcept { return a.val == b.val; }
    template <u32 mod, typename _T> constexpr bool operator == (_T a, modint<mod> b) noexcept { return modint<mod>(a) == b; }
    template <u32 mod, typename _T> constexpr bool operator == (modint<mod> a, _T b) noexcept { return a == modint<mod>(b); }
    template <u32 mod> constexpr bool operator != (modint<mod> a, modint<mod> b) noexcept { return a.val != b.val; }
    template <u32 mod, typename _T> constexpr bool operator != (_T a, modint<mod> b) noexcept { return modint<mod>(a) != b; }
    template <u32 mod, typename _T> constexpr bool operator != (modint<mod> a, _T b) noexcept { return a != modint<mod>(b); }

    template <typename iter_t>
        using is_modint_iter = std::enable_if_t<std::is_base_of<std::random_access_iterator_tag,
            typename std::iterator_traits<iter_t>::iterator_category>::value, typename std::iterator_traits<iter_t>::value_type::is_modint_t>;

    template <typename T>
        struct __idnty {
            using type = T;
        };

    template <typename iter_t, typename = is_modint_iter<iter_t>, u32 mod = std::iterator_traits<iter_t>::value_type::mod>
        constexpr void calc_power(u32 n, iter_t pw, typename __idnty<modint<mod> >::type b){//let pw_i=b^i, 0<=i<n
            if (n == 0)return;
            pw[0] = 1;
            for (u32 i = 1; i < n; ++i)pw[i] = pw[i - 1] * b;
        }

    template <typename iter_t, typename = is_modint_iter<iter_t>, u32 mod = std::iterator_traits<iter_t>::value_type::mod>
        constexpr void sieve_power(u32 n, iter_t pw, u32 e){//let pw_i=i^e, 0<=i<n
            if (n == 0)return;
            if (n == 1){
                pw[0] = 0;
                return;
            }
            bool *npr = new bool[n]{};
            u32 *prm = new u32[n <= 100? n - (n / 2) + 1 : 2 * n / std::__lg(n)]{};
            u32 l = 0;
            pw[0] = 0;
            pw[1] = 1;
            for (u32 i = 2; i < n; ++i){
                if (!npr[i]){
                    pw[i] = pow(modint<mod>(i), e);
                    prm[l++] = i;
                }
                for (u32 j = 0; j < l; ++j){
                    if (u64(i) * prm[j] >= n)break;
                    npr[i * prm[j]] = 1;
                    pw[i * prm[j]] = pw[i] * pw[prm[j]];
                    if (i % prm[j] == 0)break;
                }
            }
            delete [] npr; delete [] prm;
        }

    template <typename iter_t, typename = is_modint_iter<iter_t> >
        constexpr void calc_inv(iter_t bg, iter_t ed){//let bg[i] = bg[i]^{-1}
            constexpr u32 mod = std::iterator_traits<iter_t>::value_type::mod;
            if (bg == ed)return;
            u32 n = ed - bg;
            modint<mod> *s = new modint<mod>[n + 1];
            modint<mod> *sv = new modint<mod>[n + 1];
            s[0] = 1;
            for (u32 i = 1; i <= n; ++i)s[i] = s[i - 1] * bg[i - 1];
            sv[n] = s[n].inv();
            for (u32 i = n; i; --i)sv[i - 1] = sv[i] * bg[i - 1];
            for (u32 i = 1; i <= n; ++i)bg[i - 1] = sv[i] * s[i - 1];
            delete []s; delete []sv;
        }

    template <u32 mod> constexpr bool isnan(modint<mod> a) noexcept { return a == modint<mod>::nan; }

    // 加速求和
    template <u32 mod>
        struct accumulate_temporary_result {
            umx val;
            static constexpr umx limit = std::numeric_limits<umx>::max() - mod;
            static constexpr umx limit2 = std::numeric_limits<umx>::max() - umx(mod) * mod;
            constexpr accumulate_temporary_result() noexcept : val() {}
            constexpr accumulate_temporary_result(modint<mod> v) noexcept : val(v.value()) {}
            constexpr accumulate_temporary_result(umx v) noexcept : val(v) {}
            constexpr accumulate_temporary_result(const accumulate_temporary_result &r) noexcept : val(r.val) {}
            constexpr accumulate_temporary_result(const accumulate_temporary_result &&r) noexcept : val(r.val) {}
            template <typename _Val> constexpr accumulate_temporary_result(_Val v) noexcept : val(modval_t<mod, _Val>::modval(v)) {}
            template <typename _Val> constexpr accumulate_temporary_result &operator += (umx v) noexcept
                { if (unexpect(val >= limit))val %= mod; val += modval_t<mod, _Val>::modval(v); return *this; }
            constexpr accumulate_temporary_result &operator += (modint<mod> v) noexcept
                { if (unexpect(val >= limit))val %= mod; val += v.value(); return *this; }
            constexpr void plus_modint_prod(modint<mod> a, modint<mod> b) noexcept
                { if (unexpect(val >= limit2))val %= mod; val += umx(a.value()) * b.value(); }// += a * b
            constexpr umx value() const noexcept { return val; }
            constexpr modint<mod> mod_val() const noexcept { return modint<mod>(val); }
            constexpr operator modint<mod> () const noexcept { return modint<mod>(val); }
        };

    // 多项相加优化
    template <typename iter_t, typename iter_value_t = typename std::iterator_traits<iter_t>::value_type,
            u32 mod = iter_value_t::mod>
        constexpr modint<mod> mod_plus(iter_t bg, iter_t ed){
            typedef modint<mod> type;
            u64 sum = std::accumulate(bg, ed, u64(), [](u64 a, iter_value_t v){
                return a + type(v).value();
            });
            return type(sum);
        }
    template <typename iter_t, u32 mod = std::iterator_traits<iter_t>::value_type::mod>
        constexpr modint<mod> mod_plus(iter_t bg, u32 n){
            typedef modint<mod> type;
            if (n < 4){
                switch (n){
                    case 0: return type();
                    case 1: return *bg;
                    case 2: return *bg + *(bg + 1);
                    case 3: return *bg + *(bg + 1) + *(bg + 2);
                    default : __builtin_unreachable();
                }
            }
            return mod_plus(bg, bg + n);
        }

    // 多项相乘
    template <typename iter_t, u32 mod = std::iterator_traits<iter_t>::value_type::mod>
        constexpr modint<mod> mod_mult(iter_t bg, iter_t ed){
            typedef modint<mod> type;
            return std::accumulate(bg, ed, type(1), std::multiplies<type>{});
        }

    template <typename iter1_t, typename iter2_t,
            u32 mod = std::iterator_traits<iter1_t>::value_type::mod,
            u32 mod2 = std::iterator_traits<iter2_t>::value_type::mod,
            typename = std::enable_if_t<mod == mod2> >
        constexpr modint<mod> mod_inner_product(iter1_t bg1, iter1_t ed1, iter2_t bg2, modint<mod> init = 0){
            accumulate_temporary_result<mod> atr(init);
            for (; bg1 != ed1; ++bg1, ++bg2)atr.plus_modint_prod(*bg1, *bg2);
            return atr.mod_val();
        }

    inline namespace predefine_modint {
        using modp0 = modint<998244353>;
        using modp1 = modint<1000000007>;
        using modp2 = modint<167772161>;
        using modp3 = modint<469762049>;
        using modp4 = modint<754974721>;
        using modp5 = modint<1004535809>;
    }

}

#include <functional>

namespace std {

    using u32 = std::uint32_t;
    using u64 = std::uint64_t;

    template <u32 mod> inline ostream &operator << (ostream &os, modint_nm::modint<mod> v){ return os << v.value(); }
    template <u32 mod> inline istream &operator >> (istream &is, modint_nm::modint<mod> &v){ u64 x;is >> x;v = x;return is; }

    template <u32 mod>
        struct numeric_limits <modint_nm::modint<mod> > : numeric_limits<u32> { };

    template <u32 mod>
        struct hash<modint_nm::modint<mod> > {
            inline size_t operator () (const modint_nm::modint<mod> &v) const {
                return hash<u32>{}(v.value());
            }
        };

    template <u32 mod> constexpr modint_nm::modint<mod> fma(modint_nm::modint<mod> a,
            modint_nm::modint<mod> b, modint_nm::modint<mod> c) noexcept
        { return modint_nm::fma(a, b, c); }
    template <u32 mod> constexpr modint_nm::modint<mod> fma(modint_nm::modint<mod> a,
            modint_nm::modint<mod> b, u32 c) noexcept
        { return modint_nm::fma(a, b, c); }

}

/**
 * @todo
 * 1. 加入左移和右移支持
 * 2. 加入对卡特兰数等常见数列的支持
 * 3. 部分函数加入参数为常量时的优化
 * 4. 加入模数非质数时的除法
 */

#include <cstdint>
#include <algorithm>

namespace fact {

    using u32 = std::uint32_t;
    using u64 = std::uint64_t;

    struct default_mod {
        u32 mod;
        constexpr u32 operator () (u32 a, u32 b) noexcept {
            return u64(a) * b % mod;
        }
    };

    /// @brief 对于所有 0<=i<n,令 fc[i] = i! \bmod mod
    /// 传入的 mul 需要实现快速模乘
    template <typename val_t, typename modmul>
    constexpr void calfc(u32 n, val_t *fc, u32 mod, modmul &&mul){
        if (n == 0)return;
        if (mod == 0)throw "mod = 0.";
        if (mod == 1){
            std::fill_n(fc, n, val_t(0));
            return;
        }
        fc[0] = 1;
        for (u32 i = 1; i < n; ++i)fc[i] = mul(fc[i - 1], i);
    }
    template <typename val_t>
    constexpr void calfc(u32 n, val_t *fc, u32 mod){
        calfc(n, fc, mod, default_mod{mod});
    }

    /// @brief 对于所有 0<=i<n,令 fc[i] = i^{-1} \bmod mod,跳过 i\bmod mod = 0 的位置
    /// @pre mod 为质数
    /// 传入的 mul 需要实现快速模乘
    template <typename val_t, typename modmul>
    constexpr void caliv(u32 n, val_t *iv, u32 mod, modmul &&mul) noexcept {
        if (n == 0)return;
        if (n > mod){
            caliv(mod, iv, mod, (modmul&&)mul);
            u32 i = mod;
            for (; i + mod < n; i += mod)
                std::copy_n(iv + 1, mod - 1, iv + i + 1);
                    // 以 mod 为周期填充,即 [+1,+mod) 拷贝到 [+1+mod,2mod), [+1+2mod,3mod), ...
            std::copy_n(iv + 1, n - i - 1, iv + i + 1);
            return;
        }
        // n <= mod
        iv[1] = 1;
        for (u32 i = 2; i < n; ++i)iv[i] = mul(iv[mod % i], mod - mod / i);
    }
    template <typename val_t>
    constexpr void caliv(u32 n, val_t *iv, u32 mod) noexcept {
        caliv(n, iv, mod, default_mod{mod});
    }

    /// @brief 对于所有 0<=i<n,令 ivfc[i] = i!^{-1} \bmod mod
    /// @pre n <= mod,mod 为质数
    /// 传入的 mul 需要实现快速模乘
    template <typename val_t, typename modmul>
    constexpr void calivfc(u32 n, val_t *ivfc, u32 mod, modmul &&mul) noexcept {
        if (n == 0)return;
        caliv(n, ivfc, mod, (modmul&&)mul);
        ivfc[0] = 1;
        for (u32 i = 1; i < n; ++i)ivfc[i] = mul(ivfc[i - 1], ivfc[i]);
    }
    template <typename val_t>
    constexpr void calivfc(u32 n, val_t *ivfc, u32 mod) noexcept {
        calivfc(n, ivfc, mod, default_mod{mod});
    }

    /// @brief 求 n! \bmod mod
    /// 保证 O(n)
    /// 传入的 mul 需要实现快速模乘
    template <typename modmul>
    constexpr u32 factorial(u32 n, u32 mod, modmul &&mul) noexcept {
        if (__builtin_expect(mod == 1, false))return 0;
        if (__builtin_expect(n >= mod, false))return 0;
        u32 ret = 1;
        while (n)ret = mul(ret, n--);
        return ret;
    }
    constexpr u32 factorial(u32 n, u32 mod) noexcept {
        return factorial(n, mod, default_mod{mod});
    }

    template <typename val_t, typename modmul = default_mod>
    struct binom_base {
        modmul mul;
        const val_t *fc; // 要求构造时指向一块已经计算好阶乘的空间
        const val_t *ivfc; // 要求构造时指向一块已经计算好阶乘逆的空间
        constexpr val_t fact(u32 n) const noexcept {
            return fc[n];
        }
        constexpr val_t invfact(u32 n) const noexcept {
            return ivfc[n];
        }
    };

    struct in_range_t { } in_range;

    using i32 = std::int32_t;

    template <typename val_t, typename modmul = default_mod>
    struct combination {
        binom_base<val_t, modmul> base;
        template <typename U, typename V> constexpr auto mul(U a, V b) const noexcept { return base.mul(a, b); }
        constexpr u32 operator () (i32 n, i32 m) const noexcept
            { return ((n - m) | m) >> 31? 0 : u32(mul(base.fc[n], mul(base.ivfc[m], base.ivfc[n - m]))); }
        constexpr u32 operator () (in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.fc[n], mul(base.ivfc[m], base.ivfc[n - m])); }
        constexpr u32 iv(i32 n, i32 m) const noexcept
            { return ((n - m) | m) >> 31? u32(-1) : u32(mul(base.ivfc[n], mul(base.fc[m], base.fc[n - m]))); }
        constexpr u32 iv(in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.ivfc[n], mul(base.fc[m], base.fc[n - m])); }
    };

    template <typename val_t, typename modmul = default_mod>
    struct permutation {
        binom_base<val_t, modmul> base;
        template <typename U, typename V> constexpr auto mul(U a, V b) const noexcept { return base.mul(a, b); }
        constexpr u32 operator () (i32 n, i32 m) const noexcept
            { return ((n - m) | m) >> 31? 0 : u32(mul(base.fc[n], base.ivfc[n - m])); }
        constexpr u32 operator () (in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.fc[n], base.ivfc[n - m]); }
        constexpr u32 iv(i32 n, i32 m) const noexcept
            { return ((n - m) | m) >> 31? u32(-1) : u32(mul(base.ivfc[n], base.fc[n - m])); }
        constexpr u32 iv(in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.ivfc[n], base.fc[n - m]); }
    };

    template <typename val_t, typename modmul = default_mod>
    struct grid { // grid(n,m) : 网格 (0,0) 走到 (n,m) 的最短路径方案数,等于 C(n+m,n)
        binom_base<val_t, modmul> base;
        template <typename U, typename V> constexpr auto mul(U a, V b) const noexcept { return base.mul(a, b); }
        constexpr u32 operator () (i32 n, i32 m) const noexcept
            { return (n | m) >> 31? 0 : u32(mul(base.fc[n + m], mul(base.ivfc[n], base.ivfc[m]))); }
        constexpr u32 operator () (in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.fc[n + m], mul(base.ivfc[n], base.ivfc[m])); }
        constexpr u32 iv(i32 n, i32 m) const noexcept
            { return (n | m) >> 31? u32(-1) : u32(mul(base.ivfc[n + m], mul(base.fc[n], base.fc[m]))); }
        constexpr u32 iv(in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.ivfc[n + m], mul(base.fc[n], base.fc[m])); }
    };

    template <typename val_t, typename modmul = default_mod>
    struct split { // split(n,m) : 将 n 划分为 m 个非负整数的方案数,split(0,0)=1,其它 split(n,m)=C(n+m-1,m-1)
        binom_base<val_t, modmul> base;
        template <typename U, typename V> constexpr auto mul(U a, V b) const noexcept { return base.mul(a, b); }
        constexpr u32 operator () (i32 n, i32 m) const noexcept
            { return !m? u32(n == 0) : (n | (m - 1)) >> 31? 0 : u32(mul(base.fc[n + m - 1], mul(base.ivfc[n], base.ivfc[m - 1]))); }
        constexpr u32 operator () (in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.fc[n + m - 1], mul(base.ivfc[n], base.ivfc[m - 1])); }
        constexpr u32 iv(i32 n, i32 m) const noexcept
            { return !m? n? u32(-1) : 0 : (n | (m - 1)) >> 31? u32(-1) : u32(mul(base.ivfc[n + m - 1], mul(base.fc[n], base.fc[m - 1]))); }
        constexpr u32 iv(in_range_t, i32 n, i32 m) const noexcept
            { return mul(base.ivfc[n + m - 1], mul(base.fc[n], base.fc[m - 1])); }
    };

    /// @brief 组合数上指标求和,求 \sum_{i=m}^n \binom im
    /// binom 实现了计算组合数
    template <typename _Binom>
        constexpr auto upper_prefix_sum(u32 n, u32 m, _Binom &&binom) noexcept -> decltype(binom(u32{}, u32{})) {
            if (n < m)return 0;
            return binom(n + 1, m + 1);
        }

}

#include <bits/stdc++.h>
using namespace std;
using mod = modint_nm::modp1;
int n, k, a[310], b[310];
bool cr[610][610]; // exists cross edge
int ce[610];
inline int cem(int l, int r){
    return ce[r - 1] - ce[l - 1];
}
mod fc[610], ivfc[610];
mod piv2[610];
inline mod mt(int c){ // match 2c elem into c pairs
    return fc[c + c] * piv2[c] * ivfc[c];
}
mod f[610][610]; // f_{l,r} : [l,r) is a block
int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> k;
    fill_n(ce + 1, n + n, 1);
    for (int i = 1; i <= k; ++i)cin >> a[i] >> b[i], a[i] > b[i] && (swap(a[i], b[i]), 0), ce[a[i]] = ce[b[i]] = 0;
    for (int i = 1; i <= n + n; ++i)ce[i] += ce[i - 1];
    for (int l = 1; l <= n + n; ++l)
        for (int r = l + 1; r <= n + n; ++r)
            cr[l][r] = cr[r][l] = [&]{
                // clog << l << "~" << r << endl;
                for (int i = 1; i <= k; ++i){
                    if (l <= a[i] && b[i] < r)continue;
                    if (b[i] < l || a[i] >= r)continue;
                    if (a[i] < l && b[i] >= r)continue;
                    return 1;
                }
                return 0;
            }();
    // for (int l = 1; l <= n + n; ++l)
    //     for (int r = l + 1; r <= n + n; ++r)
    //         if (cr[l][r])clog << l << "-" << r << endl;
    fact::calfc(n + n + 1, fc, mod::mod, multiplies<>{});
    fact::calivfc(n + n + 1, ivfc, mod::mod, multiplies<>{});
    modint_nm::calc_power(n + n + 1, piv2, mod(1) / 2);
    for (int l = 1; l <= n + n; ++l)
        for (int r = l + 1; r <= n + n; ++r){
            if (cr[l][r] || (cem(l, r) & 1))continue;
            f[l][r] = mt(cem(l, r) >> 1);
            for (int k = l; k < r; ++k)
                if (~cem(k, r) & 1)
                    f[l][r] -= f[l][k] * mt(cem(k, r) >> 1);
            // clog << l << "," << r << ":" << f[l][r] << endl;
        }
    mod rs = mt(n - k);
    for (int l = 1; l <= n + n; ++l)
        for (int r = l + 1; r <= n + n; ++r){
            // [l,r) and [r,n]-[1,l)
            if (cr[l][r])continue; // exists cross
            if (cem(l, r) & 1)continue;
            // clog << l << "~" << r << ":" << f[l][r] << "*" << mt((n - k) - (cem(l, r) >> 1)) << endl;
            rs += f[l][r] * mt((n - k) - (cem(l, r) >> 1));
        }
    cout << rs << endl;
    return 0;
}

Submission Info

Submission Time
Task D - Chords
User szt100309
Language C++23 (GCC 15.2.0)
Score 900
Code Size 31840 Byte
Status AC
Exec Time 54 ms
Memory 5424 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 900 / 900
Status
AC × 3
AC × 26
Set Name Test Cases
Sample sample-01.txt, sample-02.txt, sample-03.txt
All sample-01.txt, sample-02.txt, sample-03.txt, sample-01.txt, sample-02.txt, sample-03.txt, subtask01-01.txt, subtask01-02.txt, subtask01-03.txt, subtask01-04.txt, subtask01-05.txt, subtask01-06.txt, subtask01-07.txt, subtask01-08.txt, subtask01-09.txt, subtask01-10.txt, subtask01-11.txt, subtask01-12.txt, subtask01-13.txt, subtask01-14.txt, subtask01-15.txt, subtask01-16.txt, subtask01-17.txt, subtask01-18.txt, subtask01-19.txt, subtask01-20.txt
Case Name Status Exec Time Memory
sample-01.txt AC 1 ms 3660 KiB
sample-02.txt AC 1 ms 3768 KiB
sample-03.txt AC 1 ms 3560 KiB
subtask01-01.txt AC 1 ms 3692 KiB
subtask01-02.txt AC 22 ms 5260 KiB
subtask01-03.txt AC 14 ms 5156 KiB
subtask01-04.txt AC 1 ms 3876 KiB
subtask01-05.txt AC 1 ms 3692 KiB
subtask01-06.txt AC 8 ms 5068 KiB
subtask01-07.txt AC 2 ms 4460 KiB
subtask01-08.txt AC 2 ms 4152 KiB
subtask01-09.txt AC 30 ms 5424 KiB
subtask01-10.txt AC 7 ms 5328 KiB
subtask01-11.txt AC 2 ms 5356 KiB
subtask01-12.txt AC 2 ms 4792 KiB
subtask01-13.txt AC 2 ms 4280 KiB
subtask01-14.txt AC 2 ms 3908 KiB
subtask01-15.txt AC 3 ms 5336 KiB
subtask01-16.txt AC 4 ms 5424 KiB
subtask01-17.txt AC 11 ms 5136 KiB
subtask01-18.txt AC 11 ms 4784 KiB
subtask01-19.txt AC 27 ms 4920 KiB
subtask01-20.txt AC 54 ms 5356 KiB