/* #region */ #ifdef ONLINE_JUDGE #define NDEBUG #pragma GCC optimize("O3,unroll-loops") #ifdef ATCODER #pragma GCC target("sse,sse2,sse3,ssse3,fma,abm,mmx,bmi,bmi2,popcnt,lzcnt") #pragma GCC target("avx2") // NG : CF, CodeChef, HamakoOJ #include #include #define unordered_map boost::unordered_flat_map #define unordered_set boost::unordered_flat_set #endif #endif #include // #include // using namespace atcoder; using namespace std; using namespace __gnu_pbds; // #include // #include // namespace mp = boost::multiprecision; // using lll = mp::cpp_int; // using lld = mp::cpp_dec_float_50; // 十進50桁. ldは19桁. // // using lld = mp::cpp_dec_float_100; // // using lld = mp::number>; // lld Beps = 0.00000000000000000000000000000001; // 1e-32 // const bool equals(lld a, lld b) { return mp::fabs(a - b) < Beps; } #define int ll #define endl '\n' using ll = long long; using ld = long double; constexpr ld PI = acosl(-1); constexpr ld EPS = 1e-10; constexpr int INF = 1 << 30; constexpr ll INFL = 1LL << 61; // constexpr int MOD = 998244353; constexpr int MOD = 1000000007; constexpr array dx = {0, 1, 0, -1, 1, 1, -1, -1, 0}; // → ↓ ← ↑ ↘ ↙ ↖ ↗ 自 constexpr array dy = {1, 0, -1, 0, 1, -1, -1, 1, 0}; inline namespace util { constexpr bool equals(ld a, ld b) { return fabs((a) - (b)) < EPS; } template constexpr bool overflow_if_add(T a, T b) { assert(a >= 0 && b >= 0); return (numeric_limits::max() - a) < b; } template constexpr bool overflow_if_mul(T a, T b) { // 整数型以外は未verify assert(a >= 0 && b >= 0); return (numeric_limits::max() / a) < b; } template constexpr bool overflow_if_shift(T a, int k) { assert(a >= 0); if (a == 0) return false; if (k > 64 or k < 0) return true; if (((__int128_t)a << k) > numeric_limits::max()) return true; return false; } constexpr __int128_t POW(__int128_t x, int n) { assert(n >= 0); __int128_t ret = 1; while (n > 0) { if (n & 1) ret *= x; if (n == 1) break; assert(!overflow_if_mul(x, x)); x *= x; n >>= 1; } return ret; } constexpr int64_t pow64(int64_t x, int n) { assert(n >= 0); int64_t ret = 1; while (n > 0) { if (n & 1) ret *= x; if (n == 1) break; assert(!overflow_if_mul(x, x)); x *= x; n >>= 1; } return ret; } constexpr int per(int x, int y) { // x = qy + r (0 <= r < y) を満たすq assert(y != 0); if (x >= 0 && y > 0) return x / y; if (x >= 0 && y < 0) return x / y; if (x < 0 && y < 0) return x / y + (x % y < 0); return x / y - (x % y < 0); // (x < 0 && y > 0) } constexpr int mod(int x, int y) { // x = qy + r (0 <= r < y) を満たすr assert(y != 0); return x - y * per(x, y); } // https://yukicoder.me/problems/no/2781 constexpr int floor(int x, int y) { // (ld)x / y 以下の最大の整数 assert(y != 0); if (y < 0) x = -x, y = -y; return x >= 0 ? x / y : (x + 1) / y - 1; } constexpr int ceil(int x, int y) { // (ld)x / y 以上の最小の整数 assert(y != 0); if (y < 0) x = -x, y = -y; return x > 0 ? (x - 1) / y + 1 : x / y; } constexpr int round(int x, int y) { // (ld)x / y を小数第1位について四捨五入 assert(y != 0); if (x*y < 0) return -((abs(x) * 2 + abs(y)) / (abs(y) * 2)); // https://www.acmicpc.net/problem/2108 return (x * 2 + y) / (y * 2); } constexpr int round(int x, int y, int k) { // (ld)x / y を10^kの位に関して四捨五入 assert(y != 0 && k >= 0); if (k == 0) return (x * 2 + y) / (y * 2); x /= y * POW(10, k - 1); if (x % 10 >= 5) return (x + 10 - x % 10) * POW(10, k - 1); return x * POW(10, k - 1); } constexpr int round2(int x, int y) { // 五捨五超入 // 未verify assert(y != 0); if (y < 0) y = -y, x = -x; int z = x / y; if ((z * 2 + 1) * y <= y * 2) z++; return z; } constexpr int floor(ld x) { // 未. 負数でも小さい方に丸める if (x > -EPS) return (int)(floorl(x + EPS) + EPS); return -(int)((ceill(-x - EPS)) + EPS); } constexpr int ceil(ld x) { // 未. 負数でも大きい方に丸める if (x > EPS) return (int)(ceill(x - EPS) + EPS); return -(int)((floorl(-x + EPS)) + EPS); } constexpr int round(ld x) { // 未. 負数でも.5の場合は大きい方に丸める if (x > EPS) return (int)(roundl(x + EPS) + EPS); return (int)(roundl(x + EPS) - EPS); } // constexpr int get(ld x, int k) { // 未. xの10^kの位の桁 // } constexpr ld floor(ld x, int k) { // xを10^kの位に関してflooring ld d = pow(10, -k); return floor(x * d) / d; // 未verify } constexpr ld ceil(ld x, int k) { // xを10^kの位に関してceiling ld d = pow(10, -k); return ceil(x * d) / d; // 未verify } constexpr ld round(ld x, int k) { // xを10^kの位に関して四捨五入. ld d = pow(10, -k); return round(x * d) / d; } // constexpr int kth(int x, int y, int k) { // x / yの10^kの位の桁 // } constexpr int floor(ld x, ld y) { // 誤差対策TODO assert(!equals(y, 0)); return floorl(x / y); // floor(x) = ceil(x - 1) という話も } constexpr int ceil(ld x, ld y) { // 誤差対策TODO // ceil(p/q) = -floor(-(p/q))らしい assert(!equals(y, 0)); return ceill(x / y); // ceil(x) = floor(x + 1) } constexpr int perl(ld x, ld y) { // x = qy + r (0 <= r < y, qは整数) を満たす q // 未verify. 誤差対策TODO. EPS外してもいいかも。 assert(!equals(y, 0)); if (x >= 0 && y > 0) return floorl(x / y) + EPS; if (x >= 0 && y < 0) return -floorl(x / fabs(y)); if (x < 0 && y < 0) return floorl(x / y) + (x - floorl(x/y)*y < -EPS); return floorl(x / y) - (x - floorl(x/y)*y < -EPS); // (x < 0 && y > 0) } constexpr ld modl(ld x, ld y) { // x = qy + r (0 <= r < y, qは整数) を満たす r // 未verify. 誤差対策TODO. -0.0が返りうる。 assert(!equals(y, 0)); if (x >= 0) return x - fabs(y)*fabs(perl(x, y)); return x - fabs(y)*floor(x, fabs(y)); } constexpr int seisuu(ld x) { return (int)x; } // 整数部分. 誤差対策TODO constexpr int modf(ld x) { if (x < 0) return ceil(x); else return floor(x); } // 正なら+EPS, 負なら-EPSしてから、文字列に直して小数点以下を捨てる? constexpr int seisuu(int x, int y) { assert(y != 0); return x / y; } constexpr int seisuu(ld x, ld y) { // 誤差対策TODO assert(!equals(y, 0)); return (int)(x / y); } constexpr int floor_log(int base, int x) { // log_base{x} のfloor assert(base >= 2); int ret = 0, now = 1; while (now <= x) { now *= base; if (now <= x) ret++; } return ret; } constexpr int ceil_log(int base, int x) { // log_base{x} のceil assert(base >= 2); int ret = 0, now = 1; while (now < x) { now *= base; ret++; } return ret; } template constexpr pair max(const pair &a, const pair &b) { if (a.first > b.first or a.first == b.first && a.second > b.second) return a; return b; } template constexpr pair min(const pair &a, const pair &b) { if (a.first < b.first or a.first == b.first && a.second < b.second) return a; return b; } template constexpr bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; } template constexpr bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; } template constexpr bool chmax(pair &a, const pair &b) { if (a.first < b.first or a.first == b.first && a.second < b.second) { a = b; return true; } return false; } template constexpr bool chmin(pair &a, const pair &b) { if (a.first > b.first or a.first == b.first && a.second > b.second) { a = b; return true; } return false; } template constexpr T mid(T a, T b, T c) { return max(min(a, b), min(max(a, b), c)); } template constexpr void Sort(T& a, T& b, Args&... args) noexcept { vector vec = {a, b, args...}; sort(vec.begin(), vec.end()); auto it = vec.begin(); a = *it++; b = *it++; int dummy[] = {0, (args = *it++, 0)...}; static_cast(dummy); } template constexpr void Sortr(T& a, T& b, Args&... args) noexcept { vector vec = {a, b, args...}; sort(vec.rbegin(), vec.rend()); auto it = vec.begin(); a = *it++; b = *it++; int dummy[] = {0, (args = *it++, 0)...}; static_cast(dummy); } template constexpr void sort(vector &A, vector &B) noexcept { // Aをキーにして {A[i], B[i]} をソート vector> P(A.size()); for (int i = 0; i < (int)A.size(); i++) P[i] = {A[i], B[i]}; sort(P.begin(), P.end()); for (int i = 0; i < (int)A.size(); i++) A[i] = P[i].first, B[i] = P[i].second; } istream &operator >>(istream &is, __int128_t& x) { string S; is >> S; __int128_t ret = 0; bool neg = false; if (S[0] == '-') neg = true; for (int i = neg; i < (int)S.size(); i++) { ret = ret * 10 + S[i] - '0'; } x = neg ? -ret : ret; return is; } ostream &operator <<(ostream &os, __int128_t x) { ostream::sentry s(os); if (s) { __uint128_t tmp = x < 0 ? -x : x; char buffer[128]; char *d = end(buffer); do { --d; *d = "0123456789"[tmp % 10]; tmp /= 10; } while (tmp != 0); if (x < 0) { --d; *d = '-'; } int len = end(buffer) - d; if (os.rdbuf()->sputn(d, len) != len) os.setstate(ios_base::badbit); } return os; } __int128_t abs(__int128_t x) { return x < 0 ? -x : x; } __int128_t sto128(const string &S) { assert(!S.empty()); __int128_t ret = 0; bool neg = false; if (S[0] == '-') neg = true; for (int i = neg; i < (int)S.size(); i++) { ret = ret * 10 + S[i] - '0'; } return neg ? -ret : ret; } __int128_t gcd(__int128_t a, __int128_t b) { // a = abs(a); b = abs(b); return b ? gcd(b, a % b) : a; } __int128_t lcm(__int128_t a, __int128_t b) { if (a == 0 or b == 0) return 0; // a = abs(a); b = abs(b); return a / gcd(a, b) * b; // lcmが__int128_tに収まる必要あり } string to_string(double x, int k) { // 小数第k+1を四捨五入して小数第k位までを出力 // 切り捨てがほしい場合は to_string(x, k+1) として pop_back() すればよい? assert(k >= 0); ostringstream os; os << fixed << setprecision(k) << x; return os.str(); } string to_string(__int128_t x) { if (x == 0) return "0"; string ret = ""; bool neg = false; if (x < 0) { neg = true; x = -x; } while (x) { ret += (char)('0' + x % 10); x /= 10; } if (neg) ret += '-'; reverse(ret.begin(), ret.end()); return ret; } string to_string(char c) { return string(1, c); } } inline namespace bit_function { using i64 = int64_t; constexpr int _mx = 62; // using i64 = uint64_t; constexpr int _mx = 63; // 1LLを1uLLに直す // 区間は [l, r) constexpr i64 lrmask(int l, int r) { assert(r < _mx); return (1LL << r) - (1LL << l); } constexpr i64 sub_bit(i64 x, int l, int r) { assert(r < _mx); return (x & ((1LL << r) - (1LL << l))) >> l; } // r溢れ可 constexpr i64 bit_width(i64 x) { return (x == 0) ? 1 : 64 - __builtin_clzll(x); } constexpr i64 popcount(i64 x) { return __builtin_popcountll(x); } constexpr i64 popcount(i64 x, int l, int r) { return popcount(sub_bit(x, l, r)); } constexpr i64 unpopcount(i64 x) { return bit_width(x) - popcount(x); } // 最上位bitより下のみ constexpr i64 unpopcount(i64 x, int l, int r) { return r - l - popcount(sub_bit(x, l, r)); } // 最上位bitより上も含まれうる constexpr bool is_pow2(i64 x) { return popcount(x) == 1; } constexpr bool is_pow4(i64 x) { return popcount(x) == 1 && __builtin_ctzll(x) % 2 == 0; } constexpr int top_bit(i64 x) { return (x == 0) ? -1 : 63 - __builtin_clzll(x); } constexpr int bot_bit(i64 x) { return (x == 0) ? -1 : __builtin_ctzll(x); } constexpr i64 msb(i64 x) { return (x == 0) ? 0 : 1LL << (63 - __builtin_clzll(x)); } // mask constexpr i64 lsb(i64 x) { return (x & -x); } // mask constexpr int next_bit(i64 x, int k) { assert(k < _mx - 1); i64 mask = x & ~((1LL << (k + 1)) - 1); // k+1桁目以上のビットのみ残す return (mask == 0) ? -1 : __builtin_ctzll(mask); } constexpr int prev_bit(i64 x, int k) { assert(k < _mx); i64 mask = x & ((1LL << k) - 1); // k桁目未満のビットのみ残す return (mask == 0) ? -1 : 63 - __builtin_clzll(mask); } constexpr int kth_bit(i64 x, int k) { // 下からk番目の1の位置。kは1-indexed, 位置は0-indexed if (popcount(x) < k) return -1; int pos = 0, cnt = 0; while (x > 0) { if ((x & 1) && (++cnt == k)) return pos; x >>= 1; pos++; } } constexpr int countl_zero(i64 x) { return (x == 0) ? 64 : __builtin_clzll(x); } constexpr int countr_zero(i64 x) { return (x == 0) ? 64 : __builtin_ctzll(x); } constexpr int countl_one(i64 x) { // std::countl_oneと定義が異なるので注意 if (x == 0) return 0; i64 ret = 0, k = 63 - __builtin_clzll(x); while (k != -1 && (x & (1LL << k))) { k--; ret++; } return ret; } constexpr int countr_one(i64 x) { return (x == 0) ? 0 : popcount(x ^ (x & -~x)); } constexpr i64 l_one_mask(i64 x) { // 最上位で連なってる1のmask int cnt = countl_one(x); return (cnt == 0) ? 0 : (x & (~((1LL << (bit_width(x) - cnt)) - 1))); } constexpr i64 r_one_mask(i64 x) { // 最下位で連なってる1のmask int cnt = countr_one(x); return (cnt == 0) ? 0 : (x & ((1LL << cnt) - 1)); } constexpr int floor_log2(i64 x) { assert(x > 0); return 63 - __builtin_clzll(x); } // top_bit constexpr int ceil_log2(i64 x) { assert(x > 0); return 64 - __builtin_clzll(x - 1); } constexpr i64 bit_floor(i64 x) { if (x == 0) return 0; return 1LL << (63 - __builtin_clzll(x)); } // msb constexpr i64 bit_ceil(i64 x) { if (x == 0) return 0; return 1LL << (64 - __builtin_clzll(x - 1)); } constexpr i64 rotl(i64 x, int k) { // 有効bit内でrotate. オーバーフロー注意 i64 w = bit_width(x); k = mod(k, w); assert(!overflow_if_shift(x, k)); return ((x << k) | (x >> (w - k))) & ((1LL << w) - 1); } constexpr i64 rotr(i64 x, int k) { i64 w = bit_width(x); k = mod(k, w); assert(!overflow_if_shift(x, w - k)); return ((x >> k) | (x << (w - k))) & ((1LL << w) - 1); } constexpr i64 bit_reverse(i64 x) { // 有効bit内で左右反転 i64 r = 0, w = bit_width(x); for (i64 i = 0; i < w; i++) r |= ((x >> i) & 1) << (w - i - 1); return r; } constexpr bool is_palindrome(i64 x) { return x == bit_reverse(x); } constexpr bool is_palindrome(i64 x, int l, int r) { i64 b = sub_bit(x, l, r); return b == bit_reverse(b); } constexpr i64 concat(i64 a, i64 b) { return (a << bit_width(b)) | b; } // オーバーフロー注意 constexpr i64 erase(i64 x, int l, int r) { return (x >> r << l) | (x & ((1LL << l) - 1)); } // [l, r) をカット constexpr i64 hamming(i64 a, i64 b) { return popcount(a ^ b); } constexpr i64 hamming(i64 a, i64 b, int l, int r) { return popcount(sub_bit(a, l, r) ^ sub_bit(b, l, r)); } constexpr i64 compcount(i64 x) { return (popcount(x ^ (x >> 1)) + (x & 1)) / 2; } constexpr i64 compcount2(i64 x) { return compcount(x & (x >> 1)); } // 長さ2以上の連結成分の個数 constexpr i64 adjacount(i64 x) { return popcount(x & (x >> 1)); } // 隣接する1のペアの個数 constexpr i64 next_combination(i64 x) { assert(x != 0); i64 t = x | (x - 1); return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctzll(x) + 1)); } vector popvec(i64 x) { vector ret; i64 b = 1; for (int k = 0; x >= b; k++, b <<= 1) { if (x & b) ret.push_back(k); } return ret; } } template struct Edge { int from, to; T cost; Edge() {} Edge(int to, T cost) : from(-1), to(to), cost(cost) {} Edge(int from, int to, T cost) : from(from), to(to), cost(cost) {} bool operator ==(const Edge &e) const { return this->from == e.from && this->to == e.to && this->cost == e.cost; } bool operator !=(const Edge &e) const { return this->from != e.from or this->to != e.to or this->cost != e.cost; } bool operator <(const Edge &e) const { return this->cost < e.cost; } bool operator >(const Edge &e) const { return this->cost > e.cost; } }; struct custom_hash { static uint64_t splitmix64(uint64_t x) { x += 0x9e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31); } size_t operator()(uint64_t x) const { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } }; class RNG { using state_type = uint32_t; // 負数非対応 using result_type = uint32_t; public: RNG() { auto now = chrono::high_resolution_clock::now(); w = static_cast(now.time_since_epoch().count() & 0xFFFFFFFF); } // RNG(state_type seed = 88675123) : w(seed) {} constexpr result_type Int(state_type r) { // [0, r] return _Int(r + 1); } constexpr result_type Int(state_type l, state_type r) { // [l, r] return _Int(r - l + 1) + l; } constexpr double prob() { // [0, 1] return (*this)() * INV_MAX; } constexpr double Double(double l, double r) { // [l, r] return prob() * (r - l) + l; } vector Seq(int N, state_type l, state_type r) { // [l, r] vector ret(N); for (int i = 0; i < N; i++) ret[i] = _Int(r - l + 1) + l; return ret; } vector Perm(int N) { vector ret(N); iota(ret.begin(), ret.end(), 0); for (int i = 0; i < N; i++) { int j = _Int(N - i) + i; swap(ret[i], ret[j]); } return ret; } string Str(int N, bool small = true) { string ret(N, ' '); for (int i = 0; i < N; i++) { if (small) ret[i] = (char)Int('a', 'z'); else ret[i] = (char)Int('A', 'Z'); } return ret; } private: state_type x = 123456789, y = 362436039, z = 521288629, w = 88675123; constexpr static double INV_MAX = 1.0 / 0xFFFFFFFF; constexpr result_type operator()() { state_type t = x ^ (x << 11); x = y, y = z, z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } constexpr result_type _Int(state_type r) { // [0, r) return ((uint64_t) (*this)() * r) >> 32; } } rnd; template class Compress { public: Compress() = default; template Compress(const Vecs&... vecs) { (uniqV.insert(uniqV.end(), vecs.begin(), vecs.end()), ...); sort(uniqV.begin(), uniqV.end()); uniqV.erase(unique(uniqV.begin(), uniqV.end()), uniqV.end()); sz = uniqV.size(); } int size() const noexcept { return sz; } vector zip(const vector &V) const { vector ret(V.size()); for (int i = 0; i < (int)V.size(); i++) { ret[i] = encode(V[i]); } return ret; } vector unzip(const vector &V) const { vector ret(V.size()); for (int i = 0; i < (int)V.size(); i++) { ret[i] = decode(V[i]); } return ret; } int encode(T x) const { // xが存在しない場合は挿入すべき位置を返す auto it = lower_bound(uniqV.begin(), uniqV.end(), x); return it - uniqV.begin(); } T decode(int x) const { assert(0 <= x && x < sz); return uniqV[x]; } private: int sz = 0; vector uniqV; }; class UnionFind { public: UnionFind() = default; UnionFind(int N) : par(N), sz(N, 1) { iota(par.begin(), par.end(), 0); } int root(int x) { if (par[x] == x) return x; return (par[x] = root(par[x])); } bool unite(int x, int y) { int rx = root(x); int ry = root(y); if (rx == ry) return false; if (sz[rx] < sz[ry]) swap(rx, ry); sz[rx] += sz[ry]; par[ry] = rx; return true; } bool issame(int x, int y) { return (root(x) == root(y)); } int size(int x) { return sz[root(x)]; } vector> groups() { int N = par.size(); vector> G(N); for (int x = 0; x < N; x++) { G[root(x)].push_back(x); } G.erase( remove_if(G.begin(), G.end(), [&](const vector& V) { return V.empty(); }), G.end()); return G; } private: vector par, sz; }; template class BIT { public: BIT(int N_, int x = 0) : N(N_ + 1) { bit[0].assign(N, 0); bit[1].assign(N, 0); if (x != 0) { for (int i = 0; i < N; i++) add(i, x); } } BIT(const vector &A) : N(A.size() + 1) { bit[0].assign(N, 0); bit[1].assign(N, 0); for (int i = 0; i < (int)A.size(); i++) add(i, A[i]); } void add(int l, int r, T x) { add_sub(0, l + 1, -x * l); add_sub(0, r + 1, x * r); add_sub(1, l + 1, x); add_sub(1, r + 1, -x); } void add(int i, T x) { add(i, i + 1, x); } T sum(int i) const { return sum_sub(0, i) + sum_sub(1, i) * i; } T sum(int l, int r) const { return sum(r) - sum(l); } T get(int i) const { return sum(i, i + 1); } void set(int i, T x) { T s = get(i); add(i, -s + x); } private: int N; vector bit[2]; void add_sub(int p, int i, T x) { while (i < N) { bit[p][i] += x; i += (i & -i); } } T sum_sub(int p, int i) const { T ret = T(0); while (i > 0) { ret += bit[p][i]; i -= (i & -i); } return ret; } }; inline namespace mod_util { constexpr int64_t pow_mod_constexpr(int64_t x, int64_t n, int32_t m) { assert(n >= 0); if (m == 1) return 0; uint32_t _m = (uint32_t)(m); uint64_t r = 1; uint64_t y = x % m + (x < 0 ? m : 0); while (n) { if (n & 1) r = (r * y) % _m; y = (y * y) % _m; n >>= 1; } return r; } constexpr bool is_prime_constexpr(int32_t n) { assert(n >= 0 && n <= 2147483647); if (n <= 1) return false; if (n == 2 or n == 7 or n == 61) return true; if (n % 2 == 0) return false; int64_t d = n - 1; while (d % 2 == 0) d /= 2; constexpr int64_t bases[3] = {2, 7, 61}; for (int64_t a : bases) { int64_t t = d; int64_t y = pow_mod_constexpr(a, t, n); while (t != n - 1 && y != 1 && y != n - 1) { y = y * y % n; t <<= 1; } if (y != n - 1 && t % 2 == 0) { return false; } } return true; } template class Modint { private: using u32 = std::uint_fast32_t; using u64 = std::uint_fast64_t; using i64 = std::int_fast64_t; u32 _v = 0; static constexpr bool is_prime = is_prime_constexpr(Modulus); public: static constexpr u32 mod = Modulus; constexpr Modint() noexcept = default; constexpr Modint(u64 x) noexcept : _v(util::mod(x, mod)) {} constexpr Modint(const Modint &r) noexcept = default; constexpr Modint &operator =(const Modint &r) noexcept = default; static constexpr Modint raw(u64 x) noexcept { Modint ret; ret._v = x; return ret; } constexpr u32 val() const noexcept { return _v; } constexpr Modint operator +() const noexcept { return *this; } constexpr Modint operator -() const noexcept { return raw(_v ? mod - _v : 0); } constexpr Modint operator +(const Modint &r) const noexcept { return Modint(*this) += r; } constexpr Modint operator +(int q) const noexcept { return Modint(*this) += Modint(q); } constexpr Modint operator -(const Modint &r) const noexcept { return Modint(*this) -= r; } constexpr Modint operator -(int q) const noexcept { return Modint(*this) -= Modint(q); } constexpr Modint operator *(const Modint &r) const noexcept { return Modint(*this) *= r; } constexpr Modint operator *(int q) const noexcept { return Modint(*this) *= Modint(q); } constexpr Modint operator /(const Modint &r) const noexcept { return Modint(*this) /= r; } constexpr Modint operator /(int q) const noexcept { return Modint(*this) /= Modint(q); } constexpr Modint &operator ++() noexcept { if (++_v == mod) _v = 0; return *this; } constexpr Modint operator ++(signed) noexcept { Modint tmp = *this; ++*this; return tmp; } constexpr Modint &operator --() noexcept { if (_v == 0) _v = mod; _v--; return *this; } constexpr Modint operator --(signed) noexcept { Modint tmp = *this; --*this; return tmp; } constexpr Modint &operator +=(const Modint &r) noexcept { u64 t = _v + r._v; _v = t >= mod ? t - mod : t; return *this; } constexpr Modint &operator +=(int q) noexcept { return *this += Modint(q); } constexpr Modint &operator -=(const Modint &r) noexcept { u64 t = _v + mod - r._v; _v = t >= mod ? t - mod : t; return *this; } constexpr Modint &operator -=(int q) noexcept { return *this -= Modint(q); } constexpr Modint &operator *=(const Modint &r) noexcept { _v = (u64)_v * r._v % mod; return *this; } constexpr Modint &operator *=(int q) noexcept { return *this *= Modint(q); } constexpr Modint &operator /=(const Modint &r) noexcept { return *this *= r.inv(); } constexpr Modint &operator /=(int q) noexcept { return *this /= Modint(q); } constexpr bool operator ==(const Modint &r) const noexcept { return _v == r._v; } constexpr bool operator !=(const Modint &r) const noexcept { return _v != r._v; } constexpr bool operator <(const Modint &r) const noexcept { return _v < r._v; } constexpr bool operator >(const Modint &r) const noexcept { return _v > r._v; } constexpr bool operator <=(const Modint &r) const noexcept { return _v <= r._v; } constexpr bool operator >=(const Modint &r) const noexcept { return _v >= r._v; } [[nodiscard]]constexpr Modint inv() const noexcept { if constexpr (is_prime) { return pow(mod - 2); } else { i64 a = _v, b = mod, u = 1, v = 0; while (b) { i64 t = a / b; a -= t * b; swap(a, b); u -= t * v; swap(u, v); } return raw(u < 0 ? u + mod : u); } } [[nodiscard]]constexpr Modint pow(i64 n) const noexcept { Modint ret = 1, base = *this; if (n < 0) { base = base.inv(); n = -n; } while (n) { if (n & 1) ret *= base; base *= base; n >>= 1; } return ret; } friend istream &operator >>(istream &is, Modint &x) { i64 t; is >> t; x = Modint(t); return is; } friend ostream &operator <<(ostream &os, const Modint &x) { return os << x._v; } }; using mint = Modint; int modpow(__int128_t x, int n, int mod) { if (n == 0 && mod == 1) return 0; assert(n >= 0 && mod > 0); // TODO: n <= -1 __int128_t ret = 1; x %= mod; while (n > 0) { if (n & 1) ret = ret * x % mod; x = x * x % mod; n /= 2; } return ret; } // int modinv(__int128_t x, int mod) { // // assert(mod > 0); // // assert(x > 0); // if (x == 1 or x == 0) return 1; // return mod - modinv(mod % x, mod) * (mod / x) % mod; // } } inline namespace combination { vector _fac, _finv, _inv; int _com_size = 0; void COMinit(int N) { assert(N > 0); _fac.resize(N + 1); _finv.resize(N + 1); _inv.resize(N + 1); _fac[0] = _fac[1] = 1; _finv[0] = _finv[1] = 1; _inv[1] = 1; for (int i = 2; i <= N; i++) { _fac[i] = _fac[i-1] * mint(i); _inv[i] = -_inv[MOD % i] * mint(MOD / i); _finv[i] = _finv[i - 1] * _inv[i]; } _com_size = N; } mint FAC(int N) { assert(N <= _com_size); if (N < 0) return 0; return _fac[N]; } mint FACinv(int N) { assert(N <= _com_size); if (N < 0) return 0; return _finv[N]; } mint COM(int N, int K) { assert(N <= _com_size); if (N < K) return 0; if (N < 0 or K < 0) return 0; return _fac[N] * _finv[K] * _finv[N - K]; } mint COMinv(int N, int K) { assert(N <= _com_size); if (N < K) return 0; if (N < 0 or K < 0) return 0; return _finv[N] * _fac[K] * _fac[N - K]; } mint MCOM(const vector &V) { assert(accumulate(V.begin(), V.end(), 0) <= _com_size); int N = 0; for (int i = 0; i < (int)V.size(); i++) N += V[i]; mint ret = _fac[N]; for (int i = 0; i < (int)V.size(); i++) ret *= _finv[V[i]]; return ret; } mint PERM(int N, int K) { assert(N <= _com_size); if (N < K) return 0; if (N < 0 or K < 0) return 0; return _fac[N] * _finv[N - K]; } mint NHK(int N, int K) { // initのサイズに注意 assert(N <= _com_size); // if (N < 0 or K < 0) return 0; if (N == 0 && K == 0) return 1; return COM(N + K - 1, K); } } inline namespace timer { chrono::system_clock::time_point _start; void reset() { _start = chrono::system_clock::now(); } ll now() { auto cur = chrono::system_clock::now(); return chrono::duration_cast(cur - _start).count(); } } __attribute__((constructor)) void constructor() { ios::sync_with_stdio(false); cin.tie(nullptr); cout << fixed << setprecision(10); reset(); } /* #endregion */ signed main() { COMinit(2e6 + 1); int T; cin >> T; for (int t = 0; t < T; t++) { char c, g; int N, K; cin >> c >> g >> N >> g >> K >> g; if (c == 'C') { cout << COM(N, K) << endl; } else if (c == 'P') { cout << PERM(N, K) << endl; } else { cout << NHK(N, K) << endl; } } }