結果
問題 |
No.3299 K-th MMA String
|
ユーザー |
![]() |
提出日時 | 2025-10-05 14:55:23 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
RE
|
実行時間 | - |
コード長 | 35,014 bytes |
コンパイル時間 | 3,897 ms |
コンパイル使用メモリ | 312,080 KB |
実行使用メモリ | 7,716 KB |
最終ジャッジ日時 | 2025-10-05 14:56:46 |
合計ジャッジ時間 | 6,403 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 13 WA * 1 RE * 6 |
コンパイルメッセージ
main.cpp: In static member function ‘static int ArbitraryModInt::set_mod(int)’: main.cpp:615:46: warning: no return statement in function returning non-void [-Wreturn-type] 615 | static int set_mod(int md) { mod() = md; } | ^
ソースコード
#include <bits/stdc++.h> using namespace std; #include <cassert> #include <functional> using ll = long long; using ld = long double; using Graph = vector<vector<int>>; using vi = vector<int>; using vl = vector<long long>; using vll = vector<ll>; using vb = vector<bool>; using vvi = vector<vi>; using vvl = vector<vl>; using vvb = vector<vb>; using vvvb = vector<vvb>; using vvll = vector<vll>; using vvvll = vector<vvll>; using vvvvll = vector<vvvll>; using vvvvvll = vector<vvvvll>; using vd = vector<double>; using vvd = vector<vd>; using vvvd = vector<vvd>; using vld = vector<long double>; using vvld = vector<vld>; using vvvld = vector<vvld>; using vc = vector<char>; using vvc = vector<vc>; using lll = __int128_t; using vs = vector<string>; using pii = pair<long long, long long>; #define mp make_pair #define reps(i, a, n) for (ll i = (a); i < (ll)(n); i++) #define rep(i, n) for (ll i = (0); i < (ll)(n); i++) #define rrep(i, n) for (ll i = (1); i < (ll)(n + 1); i++) #define repd(i, n) for (ll i = n - 1; i >= 0; i--) #define rrepd(i, n) for (ll i = n; i >= 1; i--) #define ALL(n) n.begin(), n.end() #define rALL(n) n.rbegin(), n.rend() #define fore(i, a) for (auto &i : a) #define IN(a, x, b) (a <= x && x < b) #define IN(a, x, b) (a <= x && x < b) #define INIT \ std::ios::sync_with_stdio(false); \ std::cin.tie(0); template <typename T> // [0,M)についての階上を求める vector<T> KAI(int M) { vector<T> kai(M, 1); rep(i, M - 1) { kai[i + 1] = kai[i] * (i + 1); } return kai; } template <typename T> vector<T> DIV(int M) { vector<T> kai = KAI<T>(M), div(M, 1); rep(i, M - 1) { div[i + 1] = 1 / kai[i + 1]; } return div; } long long Power(long long a, long long b, long long m) { long long p = a, Answer = 1; p %= m; for (int i = 0; i < 63; i++) { ll wari = (1LL << i); if ((b / wari) % 2 == 1) { Answer %= m; Answer = (Answer * p) % m; // 「a の 2^i 乗」が掛けられるとき } ll t = p % m; p = (t * t) % m; // cout << p << endl; } return Answer; } // a ÷ b を m で割った余りを返す関数 long long Division(long long a, long long b, long long m) { return (a * Power(b, m - 2, m)) % m; } template <class T> void output(T &W, bool x) { cout << W; if (!x) cout << ' '; else cout << '\n'; return; } // sは改行するか否かを表す template <class T> void output(vector<T> &W, bool s) { rep(i, W.size()) { output(W[i], ((i == W.size() - 1) || s)); } return; } // sは改行するか否かを表す template <class T> void output(vector<vector<T>> &W, bool s) { rep(i, W.size()) { output(W[i], s); } return; } template <class T> T vectorsum(vector<T> &W, int a, int b) { return accumulate(W.begin() + a, W.end() + b, (T)0); } template <class T> T vectorsum(vector<T> &W) { int b = W.size(); return accumulate(ALL(W), (T)0); } template <class T> inline T CHMAX(T &a, const T b) { return a = (a < b) ? b : a; } template <class T> inline T CHMIN(T &a, const T b) { return a = (a > b) ? b : a; } template <class T> void input(T &W) { cin >> W; return; } template <class T> void input(vector<T> &W) { for (auto &u : W) input(u); return; } template <class T, class TT> void add(T &W, TT &a) { W += a; return; } template <class T> void add(vector<T> &W, vector<T> &a) { rep(i, W.size()) add(W[i], a[i]); } template <class T> void add(T &W, T &a) { W += a; } template <class T, class TT> void add(vector<T> &W, TT a) { for (auto &u : W) add(u, a); return; } const double PI = acos(-1.0L); const long double EPS = 1e-10; const double INF = 1e18; struct TRI { ll a; ll b; ll c; ll d; }; bool operator>(const TRI &r, const TRI &l) { return (r.a > l.a | (r.a == l.a & r.b > l.b) | (r.a == l.a & r.b == l.b & r.c > l.c)); } bool operator<(const TRI &r, const TRI &l) { return (r.a < l.a | (r.a == l.a & r.b < l.b) | (r.a == l.a & r.b == l.b & r.c < l.c)); } struct TRK { ll a; ll b; ll c; }; bool operator>(const TRK &r, const TRK &l) { return (r.a > l.a | (r.a == l.a & r.b > l.b) | (r.a == l.a & r.b == l.b & r.c > l.c)); } bool operator<(const TRK &r, const TRK &l) { return (r.a < l.a | (r.a == l.a & r.b < l.b) | (r.a == l.a & r.b == l.b & r.c < l.c)); } #include <bits/stdc++.h> using namespace std; // 実装はUnion by sizeで行っている class UnionFind { public: UnionFind() = default; /// @param n 要素数 explicit UnionFind(size_t n) : m_parentsOrSize(n, -1), N(n) {} /// @brief 頂点 i の root のインデックスを返します。 /// @param i 調べる頂点のインデックス /// @return 頂点 i の root のインデックス int leader(int i) { if (m_parentsOrSize[i] < 0) { return i; } const int root = leader(m_parentsOrSize[i]); // 経路圧縮 return (m_parentsOrSize[i] = root); } /// @param w (b の重み) - (a の重み) /// a を含むグループと b を含むグループを併合する // グループが一致している場合何もしない void merge(int a, int b) { a = leader(a); b = leader(b); if (a != b) { // union by size (小さいほうが子になる) if (-m_parentsOrSize[a] < -m_parentsOrSize[b]) { std::swap(a, b); } m_parentsOrSize[a] += m_parentsOrSize[b]; m_parentsOrSize[b] = a; } } /// @brief a と b が同じグループに属すかを返します。 /// @param a 一方のインデックス /// @param b 他方のインデックス /// @return a と b が同じグループに属す場合 true, それ以外の場合は false /// a と b が同じグループに属すかを返す bool same(int a, int b) { return (leader(a) == leader(b)); } /// @brief i が属するグループの要素数を返します。 /// @param i インデックス /// @return i が属するグループの要素数 int size(int i) { return -m_parentsOrSize[leader(i)]; } vector<vector<int>> Groups() { vector<vector<int>> G; int sum = 0; vector<int> number(N, -1); for (int i = 0; i < N; i++) { int a = leader(i); if (number[a] == -1) { number[a] = sum; G.emplace_back(vector<int>{}); G[sum].emplace_back(i); sum++; } else { G[number[i]].emplace_back(i); } } return G; } private: // m_parentsOrSize[i] は i の 親, // ただし root の場合は (-1 * そのグループに属する要素数) int N; std::vector<int> m_parentsOrSize; }; struct Mo { int n; vector<pair<int, int>> lr; explicit Mo(int n) : n(n) {} void add(int l, int r) { /* [l, r) */ lr.emplace_back(l, r); } template <typename AL, typename AR, typename EL, typename ER, typename O> void build(const AL &add_left, const AR &add_right, const EL &erase_left, const ER &erase_right, const O &out) { int q = (int)lr.size(); int bs = n / min<int>(n, sqrt(q)); vector<int> ord(q); iota(begin(ord), end(ord), 0); sort(begin(ord), end(ord), [&](int a, int b) { int ablock = lr[a].first / bs, bblock = lr[b].first / bs; if (ablock != bblock) return ablock < bblock; return (ablock & 1) ? lr[a].second > lr[b].second : lr[a].second < lr[b].second; }); int l = 0, r = 0; for (auto idx : ord) { while (l > lr[idx].first) add_left(--l); while (r < lr[idx].second) add_right(r++); while (l < lr[idx].first) erase_left(l++); while (r > lr[idx].second) erase_right(--r); out(idx); } } template <typename A, typename E, typename O> void build(const A &add, const E &erase, const O &out) { build(add, add, erase, erase, out); } }; vector<bool> Eratosthenes(int N) { vector<bool> R(N + 1, true); R[0] = R[1] = false; for (int p = 2; p <= N; ++p) { if (!R[p]) continue; for (int q = p * 2; q <= N; q += p) { R[q] = false; } } return R; } #include <bits/stdc++.h> using namespace std; // 抽象化セグメント木 template <typename T> struct segment_tree { private: int n{}, sz{}, height{}; vector<T> node; T (*combine)(T, T); // 区間の結合を行う演算 T (*identity)(); // 単位元 void update(int k) { node[k] = combine(node[2 * k], node[2 * k + 1]); } public: segment_tree() {} segment_tree(int n, T (*combine)(T, T), T (*identity)()) : n(n), combine(combine), identity(identity) { sz = 1; height = 0; while (sz < n) sz <<= 1, height++; node = vector<T>(2 * sz, identity()); } segment_tree(vector<T> &A, T (*combine)(T, T), T (*identity)()) : n((int)A.size()), combine(combine), identity(identity) { sz = 1; height = 0; while (sz < n) sz <<= 1, height++; node = vector<T>(2 * sz, identity()); for (int i = 0; i < (int)A.size(); i++) { node[sz + i] = A[i]; } for (int i = sz - 1; i > 0; --i) { node[i] = combine(node[2 * i], node[2 * i + 1]); } } T get(int k) { return node[k + sz]; } T operator[](int i) { assert(0 <= i && i < n); return node[i + sz]; } void set(int i, T x) { assert(0 <= i && i < n); i += sz; node[i] = x; for (int k = 1; k <= height; k++) update(i >> k); } T prod(int l, int r) { assert(0 <= l && l <= r && r <= n); T res = identity(); // 初期値は単位元 T res2 = identity(); for (l += sz, r += sz; l < r; l >>= 1, r >>= 1) { // 区間内のものを左右から結合 if (l & 1) res = combine(res, node[l++]); if (r & 1) res2 = combine(node[--r], res2); } return combine(res, res2); } T all_prod() { return prod(0, n); } template <typename C> int max_right(int l, const C &check) { if (l >= n) return n; l += sz; T sum = identity(); do { while ((l & 1) == 0) l >>= 1; if (!check(combine(sum, node[l]))) { while (l < sz) { l <<= 1; auto nxt = combine(sum, node[l]); if (check(nxt)) { sum = nxt; l++; } } return l - sz; } sum = combine(sum, node[l++]); } while ((l & -l) != l); return n; } template <typename C> int min_left(int r, const C &check) { if (r <= 0) return 0; r += sz; T sum = identity(); do { r--; while (r > 1 and (r & 1)) r >>= 1; if (!check(combine(node[r], sum))) { while (r < sz) { r = (r << 1) + 1; auto nxt = combine(node[r], sum); if (check(nxt)) { sum = nxt; r--; } } return r - sz; } sum = combine(node[r], sum); } while ((r & -r) != r); return 0; } }; void Yes(bool b) { if (b) cout << "Yes" << '\n'; else cout << "No" << '\n'; } // 参考(https://pione.hatenablog.com/entry/2021/02/27/061552) class Dinic { private: const int INF = 1e9; vector<int> level, itr; struct Edge { int to, rev; int cap; Edge(int to, int rev, int cap) : to(to), rev(rev), cap(cap) {}; }; vector<vector<Edge>> G; Edge &get_rev(Edge &edge) { return G[edge.to][edge.rev]; } void bfs(int s) { level.assign(G.size(), -1); level[s] = 0; queue<int> q; q.push(s); while (!q.empty()) { auto v = q.front(); q.pop(); for (auto &e : G[v]) { if (level[e.to] < 0 and e.cap > 0) { level[e.to] = level[v] + 1; q.push(e.to); } } } } int dfs(int v, int t, int flow) { if (v == t) return flow; for (int &i = itr[v]; i < G[v].size(); i++) { auto &edge = G[v][i]; if (level[v] < level[edge.to] and edge.cap > 0) { auto f = dfs(edge.to, t, min(flow, edge.cap)); if (f > 0) { edge.cap -= f; get_rev(edge).cap += f; return f; } } } return 0; } public: Dinic(int n) { G.resize(n); } void add_edge(int from, int to, int cap) { G[from].push_back(Edge(to, (int)G[to].size(), cap)); G[to].push_back(Edge(from, (int)G[from].size() - 1, 0)); } int get_max_flow(int s, int t) { int n = G.size(); int res = 0; while (true) { itr.assign(n, 0); bfs(s); if (level[t] < 0) break; while (true) { int flow = dfs(s, t, INF); if (flow > 0) res += flow; else break; } } return res; } }; vvll G; /*https://ei1333.github.io/luzhiled/snippets/math/fast-fourier-transform.html*/ namespace FastFourierTransform { using real = double; struct C { real x, y; C() : x(0), y(0) {} C(real x, real y) : x(x), y(y) {} inline C operator+(const C &c) const { return C(x + c.x, y + c.y); } inline C operator-(const C &c) const { return C(x - c.x, y - c.y); } inline C operator*(const C &c) const { return C(x * c.x - y * c.y, x * c.y + y * c.x); } inline C conj() const { return C(x, -y); } }; const real PI = acosl(-1); int base = 1; vector<C> rts = {{0, 0}, {1, 0}}; vector<int> rev = {0, 1}; void ensure_base(int nbase) { if (nbase <= base) return; rev.resize(1 << nbase); rts.resize(1 << nbase); for (int i = 0; i < (1 << nbase); i++) { rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1)); } while (base < nbase) { real angle = PI * 2.0 / (1 << (base + 1)); for (int i = 1 << (base - 1); i < (1 << base); i++) { rts[i << 1] = rts[i]; real angle_i = angle * (2 * i + 1 - (1 << base)); rts[(i << 1) + 1] = C(cos(angle_i), sin(angle_i)); } ++base; } } void fft(vector<C> &a, int n) { assert((n & (n - 1)) == 0); int zeros = __builtin_ctz(n); ensure_base(zeros); int shift = base - zeros; for (int i = 0; i < n; i++) { if (i < (rev[i] >> shift)) { swap(a[i], a[rev[i] >> shift]); } } for (int k = 1; k < n; k <<= 1) { for (int i = 0; i < n; i += 2 * k) { for (int j = 0; j < k; j++) { C z = a[i + j + k] * rts[j + k]; a[i + j + k] = a[i + j] - z; a[i + j] = a[i + j] + z; } } } } vector<int64_t> multiply(const vector<int> &a, const vector<int> &b) { int need = (int)a.size() + (int)b.size() - 1; int nbase = 1; while ((1 << nbase) < need) nbase++; ensure_base(nbase); int sz = 1 << nbase; vector<C> fa(sz); for (int i = 0; i < sz; i++) { int x = (i < (int)a.size() ? a[i] : 0); int y = (i < (int)b.size() ? b[i] : 0); fa[i] = C(x, y); } fft(fa, sz); C r(0, -0.25 / (sz >> 1)), s(0, 1), t(0.5, 0); for (int i = 0; i <= (sz >> 1); i++) { int j = (sz - i) & (sz - 1); C z = (fa[j] * fa[j] - (fa[i] * fa[i]).conj()) * r; fa[j] = (fa[i] * fa[i] - (fa[j] * fa[j]).conj()) * r; fa[i] = z; } for (int i = 0; i < (sz >> 1); i++) { C A0 = (fa[i] + fa[i + (sz >> 1)]) * t; C A1 = (fa[i] - fa[i + (sz >> 1)]) * t * rts[(sz >> 1) + i]; fa[i] = A0 + A1 * s; } fft(fa, sz >> 1); vector<int64_t> ret(need); for (int i = 0; i < need; i++) { ret[i] = llround(i & 1 ? fa[i >> 1].y : fa[i >> 1].x); } return ret; } }; // namespace FastFourierTransform /*https://ei1333.github.io/luzhiled/snippets/math/mod-int.html*/ struct ArbitraryModInt { int x; ArbitraryModInt() : x(0) {} ArbitraryModInt(int64_t y) : x(y >= 0 ? y % mod() : (mod() - (-y) % mod()) % mod()) {} static int &mod() { static int mod = 0; return mod; } static int set_mod(int md) { mod() = md; } ArbitraryModInt &operator+=(const ArbitraryModInt &p) { if ((x += p.x) >= mod()) x -= mod(); return *this; } ArbitraryModInt &operator-=(const ArbitraryModInt &p) { if ((x += mod() - p.x) >= mod()) x -= mod(); return *this; } ArbitraryModInt &operator*=(const ArbitraryModInt &p) { unsigned long long a = (unsigned long long)x * p.x; unsigned xh = (unsigned)(a >> 32), xl = (unsigned)a, d, m; asm("divl %4; \n\t" : "=a"(d), "=d"(m) : "d"(xh), "a"(xl), "r"(mod())); x = m; return *this; } ArbitraryModInt &operator/=(const ArbitraryModInt &p) { *this *= p.inverse(); return *this; } ArbitraryModInt operator-() const { return ArbitraryModInt(-x); } ArbitraryModInt operator+(const ArbitraryModInt &p) const { return ArbitraryModInt(*this) += p; } ArbitraryModInt operator-(const ArbitraryModInt &p) const { return ArbitraryModInt(*this) -= p; } ArbitraryModInt operator*(const ArbitraryModInt &p) const { return ArbitraryModInt(*this) *= p; } ArbitraryModInt operator/(const ArbitraryModInt &p) const { return ArbitraryModInt(*this) /= p; } bool operator==(const ArbitraryModInt &p) const { return x == p.x; } bool operator!=(const ArbitraryModInt &p) const { return x != p.x; } ArbitraryModInt inverse() const { int a = x, b = mod(), u = 1, v = 0, t; while (b > 0) { t = a / b; swap(a -= t * b, b); swap(u -= t * v, v); } return ArbitraryModInt(u); } ArbitraryModInt pow(int64_t n) const { ArbitraryModInt ret(1), mul(x); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } friend ostream &operator<<(ostream &os, const ArbitraryModInt &p) { return os << p.x; } friend istream &operator>>(istream &is, ArbitraryModInt &a) { int64_t t; is >> t; a = ArbitraryModInt(t); return (is); } }; /*https://ei1333.github.io/luzhiled/snippets/math/mod-int.html*/ template <int mod = 1000000007> struct ModInt { int x; ModInt() : x(0) {} ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {} ModInt &operator+=(const ModInt &p) { if ((x += p.x) >= mod) x -= mod; return *this; } ModInt &operator-=(const ModInt &p) { if ((x += mod - p.x) >= mod) x -= mod; return *this; } ModInt &operator*=(const ModInt &p) { x = (int)(1LL * x * p.x % mod); return *this; } ModInt &operator/=(const ModInt &p) { *this *= p.inverse(); return *this; } ModInt operator-() const { return ModInt(-x); } ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; } ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; } ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; } ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; } bool operator==(const ModInt &p) const { return x == p.x; } bool operator!=(const ModInt &p) const { return x != p.x; } ModInt inverse() const { int a = x, b = mod, u = 1, v = 0, t; while (b > 0) { t = a / b; swap(a -= t * b, b); swap(u -= t * v, v); } return ModInt(u); } ModInt pow(int64_t n) const { ModInt ret(1), mul(x); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; } friend istream &operator>>(istream &is, ModInt &a) { int64_t t; is >> t; a = ModInt<mod>(t); return (is); } static int get_mod() { return mod; } }; using modint = ModInt<1000000007>; /* https://ei1333.github.io/luzhiled/snippets/math/arbitrary-mod-convolution.html */ // Sはdataを表している。 template <typename T> struct ArbitraryModConvolution { using real = FastFourierTransform::real; using C = FastFourierTransform::C; ArbitraryModConvolution() = default; vector<T> multiply(const vector<T> &a, const vector<T> &b, int need = -1) { if (need == -1) need = a.size() + b.size() - 1; int nbase = 0; while ((1 << nbase) < need) nbase++; FastFourierTransform::ensure_base(nbase); int sz = 1 << nbase; vector<C> fa(sz); for (int i = 0; i < a.size(); i++) { fa[i] = C(a[i].x & ((1 << 15) - 1), a[i].x >> 15); } fft(fa, sz); vector<C> fb(sz); if (a == b) { fb = fa; } else { for (int i = 0; i < b.size(); i++) { fb[i] = C(b[i].x & ((1 << 15) - 1), b[i].x >> 15); } fft(fb, sz); } real ratio = 0.25 / sz; C r2(0, -1), r3(ratio, 0), r4(0, -ratio), r5(0, 1); for (int i = 0; i <= (sz >> 1); i++) { int j = (sz - i) & (sz - 1); C a1 = (fa[i] + fa[j].conj()); C a2 = (fa[i] - fa[j].conj()) * r2; C b1 = (fb[i] + fb[j].conj()) * r3; C b2 = (fb[i] - fb[j].conj()) * r4; if (i != j) { C c1 = (fa[j] + fa[i].conj()); C c2 = (fa[j] - fa[i].conj()) * r2; C d1 = (fb[j] + fb[i].conj()) * r3; C d2 = (fb[j] - fb[i].conj()) * r4; fa[i] = c1 * d1 + c2 * d2 * r5; fb[i] = c1 * d2 + c2 * d1; } fa[j] = a1 * b1 + a2 * b2 * r5; fb[j] = a1 * b2 + a2 * b1; } fft(fa, sz); fft(fb, sz); vector<T> ret(need); for (int i = 0; i < need; i++) { int64_t aa = llround(fa[i].x); int64_t bb = llround(fb[i].x); int64_t cc = llround(fa[i].y); aa = T(aa).x, bb = T(bb).x, cc = T(cc).x; ret[i] = aa + (bb << 15) + (cc << 30); } return ret; } }; // 参考(https://nyaannyaan.github.io/library/data-structure-2d/2d-segment-tree.hpp.html) template <typename T, typename F> struct SegmentTree2D { private: int id(int h, int w) const { return h * 2 * W + w; } public: int H, W; vector<T> seg; const F f; const T I; SegmentTree2D(int h, int w, F _f, const T &i) : f(_f), I(i) { init(h, w); } void init(int h, int w) { H = W = 1; while (H < h) H <<= 1; while (W < w) W <<= 1; seg.assign(4 * H * W, I); } // build にのみ呼ぶ void set(int h, int w, const T &x) { seg[id(h + H, w + W)] = x; } void build() { // w in [W, 2W) for (int w = W; w < 2 * W; w++) { for (int h = H - 1; h; h--) { seg[id(h, w)] = f(seg[id(2 * h + 0, w)], seg[id(2 * h + 1, w)]); } } // h in [0, 2H) for (int h = 0; h < 2 * H; h++) { for (int w = W - 1; w; w--) { seg[id(h, w)] = f(seg[id(h, 2 * w + 0)], seg[id(h, 2 * w + 1)]); } } } T get(int h, int w) const { return seg[id(h + H, w + W)]; } T operator()(int h, int w) const { return seg[id(h + H, w + W)]; } void update(int h, int w, const T &x) { h += H, w += W; seg[id(h, w)] = x; for (int i = h >> 1; i; i >>= 1) { seg[id(i, w)] = f(seg[id(2 * i + 0, w)], seg[id(2 * i + 1, w)]); } for (; h; h >>= 1) { for (int j = w >> 1; j; j >>= 1) { seg[id(h, j)] = f(seg[id(h, 2 * j + 0)], seg[id(h, 2 * j + 1)]); } } } T _inner_query(int h, int w1, int w2) { T res = I; for (; w1 < w2; w1 >>= 1, w2 >>= 1) { if (w1 & 1) res = f(res, seg[id(h, w1)]), w1++; if (w2 & 1) --w2, res = f(res, seg[id(h, w2)]); } return res; } // [ (h1,w1), (h2,w2) ) 半開 T query(int h1, int w1, int h2, int w2) { if (h1 >= h2 || w1 >= w2) return I; T res = I; h1 += H, h2 += H, w1 += W, w2 += W; for (; h1 < h2; h1 >>= 1, h2 >>= 1) { if (h1 & 1) res = f(res, _inner_query(h1, w1, w2)), h1++; if (h2 & 1) --h2, res = f(res, _inner_query(h2, w1, w2)); } return res; } }; /** * @brief 二次元セグメント木 * @docs docs/data-structure-2d/2d-segment-tree.md */ using S = ll; using S2 = ll; // 区間取得をどのようにするかを定義する。RMQだったらmin(a,b)とかになる。 S op(S a, S b) { return max(a, b); }; S e() { return -1; } S op2(S a, S b) { return min(a, b); }; S e2() { return 1e9; } /* binary_trie insert(x,w): xをw個追加する。 insert(x,w): xを1個追加する。 erase(x,w): xをw個削除する。 erase(x): xを全て削除する。 search(x):xを個数を調べる count(): binary_trieにある数字の個数。 at(k): binary_trieのk(0-index)番目に小さい要素の数 count_ress_eq(x): x以下の要素の個数 count_ress(x): x未満の要素の個数 count_upper_eq(x): x以上の要素の個数 count_upper(x): xより大きい要素の個数 erement_ress_eq(x): x以下の要素のうち最大の要素を出力 erement_ress(x): x未満の要素のうち最大の要素を出力 erament_upper_eq(x): x以上の要素のうち最小の要素の出力 eremant_upper(x): xより大きいx以下の要素のうち最大の要素を出力 */ #include <bits/stdc++.h> using namespace std; template <typename T> struct binary_trie { struct Node { // 頂点を表す構造体 std::array<int, 2> next; // 子の頂点番号を格納。存在しなければ-1 long long common; // いくつの単語がこの頂点を共有しているか Node() : common(0) { next.fill(-1); }; }; // (2^depthまでの桁をみる) vector<Node> nodes; // trie 木本体 int root; int depth = 60; binary_trie() : root(0) { nodes.push_back(Node()); } binary_trie(int dep) : root(0), depth(dep) { nodes.push_back(Node()); } // 任意の数の数字を追加する void insert(const T &word, long long number) { int node_id = 0; for (int i = depth; i > -1; i--) { int c = (word >> i) & 1; // cout << next_id << ' ' << node_id <<' // '<<nodes[node_id].next.size() <<' ' <<c << endl; if (nodes[node_id].next.at(c) == -1) { // 次の頂点が存在しなければ追加 nodes[node_id].next.at(c) = (int)nodes.size(); nodes.emplace_back(Node()); } nodes[node_id].common += number; node_id = nodes[node_id].next.at(c); ; } nodes[node_id].common += number; } // 数を1個追加する void insert(const T &word) { insert(word, 1); } // 削除処理:number個存在するなら削除して、そうでない場合は何もしない) void erase(const T &word, long long number) { if (number == 0) return; int node_id = 0; stack<int> S; for (int i = depth; i > -1; i--) { nodes[node_id].common -= number; int c = (word >> i) & 1; if (nodes[node_id].next.at(c) == -1) { // 次の頂点が存在しなければ修了 return; } node_id = nodes[node_id].next.at(c); } nodes[node_id].common -= number; } // wordの要素を全削除 void erase(const T &word) { return erase(word, search(word)); } // 数字の個数の検索 long long search(const T &word) { int node_id = 0; for (int i = depth; i > -1; i--) { int c = (word >> i) & 1; if (nodes[node_id].next[c] == -1) { // 次の頂点が存在しなければ終了 return 0; } node_id = nodes[node_id].next[c]; } // 0個のノードも存在する return nodes[node_id].common; } // binary_trieに存在する要素の個数 int count() { return nodes[0].common; } // binary_trieに存在する要素の最大値(要素自体が無ければ-1を出力) T maximum() { long long sum = 0; if (nodes[0].common == 0) return -1; int node_id = 0; for (int i = depth; i > -1; i--) { int next_id = nodes[node_id].next.at(1); if (next_id != -1) { if (nodes[next_id].common > 0) { sum += (1LL << i); node_id = next_id; } } else node_id = nodes[node_id].next.at(0); } return sum; } // binary_trieに存在する要素の最小値(要素自体が無ければ-1を出力) T minimum() { T sum = 0; if (nodes[0].common == 0) return -1; int node_id = 0; for (int i = depth; i > -1; i--) { int next_id = nodes[node_id].next.at(0); if (next_id != -1) { if (nodes[next_id].common > 0) { node_id = next_id; } } else { sum += (1LL << i); node_id = nodes[node_id].at(1); } } return sum; } // binary_trieの小さい順からk(0-index)番目の要素(要素自体が無ければ-1を出力) T at(int k) { // 範囲外参照した場合-1を出力する。 if (k < 0 || k >= count()) { return -1; } int x = k; T sum = 0; int node_id = 0; for (int i = depth; i > -1; i--) { int next_id = nodes[node_id].next[0]; if (next_id != -1) { if (nodes[next_id].common > x) { node_id = next_id; } else { sum += (1LL << i); node_id = nodes[node_id].next[1]; x -= nodes[next_id].common; } } else { sum += (1LL << i); node_id = nodes[node_id].next[1]; } if (node_id == -1) break; } return sum; } // word以下の要素の数 int count_ress_eq(T word) { int sum = 0; int node_id = 0; for (int i = depth; i > -1; i--) { int next_id = nodes[node_id].next[0]; // wordのi桁目が1のビットのとき操作を終えた後、i桁目が1であるものに移動する。 if ((word >> i) & 1) { // i桁目が0の場合、明らかに下回るのでその個数を追加する。 if (next_id != -1) sum += nodes[next_id].common; node_id = nodes[node_id].next[1]; } // それ意外の場合、i桁目が0であるものに移動する。 else node_id = next_id; if (node_id == -1) { break; } } // word に等しくなる要素の個数の追加 if (node_id != -1) sum += nodes[node_id].common; return sum; } // word未満の要素の数 int count_ress(T word) { int sum = 0; int node_id = 0; for (int i = depth; i > -1; i--) { int next_id = nodes[node_id].next[0]; // wordのi桁目が1のビットのとき操作を終えた後、i桁目が1であるものに移動する。 if ((word >> i) & 1) { // i桁目が0の場合、明らかに下回るのでその個数を追加する。 if (next_id != -1) sum += nodes[next_id].common; node_id = nodes[node_id].next[1]; } // それ意外の場合、i桁目が0であるものに移動する。 else node_id = next_id; if (node_id == -1) { break; } } return sum; } // word以上の要素の数 int count_upper_eq(const T &word) { return (count() - count_ress(word)); } // wordよりも大きい要素の数 int count_upper(const T &word) { return count() - count_ress_eq(word); } // wordよりも小さい要素の中で最大の要素を出力 T erement_ress(const T &word) { return at(count_ress(word) - 1); } // word以下の要素の中で最大の要素を出力 T erement_ress_eq(const T &word) { return at(count_ress_eq(word) - 1); } // word以上の要素の中で最小の要素を出力 T erement_upper_eq(const T &word) { return at(count_ress(word)); } // wordよりも大きい要素の中で最小の要素を出力 T erement_upper(T word) { return at(count_ress_eq(word + 1)); } T reat(int k) { return at(count() - 1 - k); } }; void solve() { ll M, N, K; ll t; ll a = 0, b, c, d; ll x = 1; string S, T; cin >> N >> M; ll count = 0; a = min(N, 16LL); vs X; rep(i, (1LL << a)) { rep(j, a - 2) { if ((i & (1LL << j)) && (i & (1LL << (j + 1))) && !(i & (1LL << (j + 2)))) { S = ""; rep(j, a) { if ((i & (1LL << j))) S.push_back('M'); else S.push_back('A'); } X.emplace_back(S); break; } } } sort(ALL(X)); rep(i, N - a) { cout << 'A'; } cout << X[M - 1] << '\n'; // cout << count << '\n'; } int main() { cin.tie(0)->sync_with_stdio(0); cout << fixed << setprecision(50); ll t; t = 1; // cin >> t; rep(_, t) solve(); }