結果
問題 | No.2997 Making YuzuKizu |
ユーザー | ルク |
提出日時 | 2024-12-04 17:56:21 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 5 ms / 2,000 ms |
コード長 | 32,070 bytes |
コンパイル時間 | 12,965 ms |
コンパイル使用メモリ | 465,656 KB |
実行使用メモリ | 5,248 KB |
最終ジャッジ日時 | 2024-12-21 23:34:50 |
合計ジャッジ時間 | 10,952 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 5 ms
5,248 KB |
testcase_02 | AC | 5 ms
5,248 KB |
testcase_03 | AC | 5 ms
5,248 KB |
testcase_04 | AC | 2 ms
5,248 KB |
testcase_05 | AC | 2 ms
5,248 KB |
testcase_06 | AC | 2 ms
5,248 KB |
testcase_07 | AC | 2 ms
5,248 KB |
testcase_08 | AC | 2 ms
5,248 KB |
testcase_09 | AC | 2 ms
5,248 KB |
testcase_10 | AC | 3 ms
5,248 KB |
testcase_11 | AC | 2 ms
5,248 KB |
testcase_12 | AC | 2 ms
5,248 KB |
testcase_13 | AC | 2 ms
5,248 KB |
testcase_14 | AC | 2 ms
5,248 KB |
testcase_15 | AC | 2 ms
5,248 KB |
testcase_16 | AC | 2 ms
5,248 KB |
testcase_17 | AC | 2 ms
5,248 KB |
ソースコード
#pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #if __has_include(<bits/stdc++.h>) #include <bits/stdc++.h> using namespace std; #endif #if __has_include(<boost/multiprecision/cpp_int.hpp>) #include <boost/multiprecision/cpp_int.hpp> using namespace boost::multiprecision; #endif #if __has_include(<atcoder/all>) #include <atcoder/all> using namespace atcoder; using mint = modint998244353; using MINT = modint1000000007; #endif #if __has_include("./cpp-dump/cpp-dump.hpp") #include "./cpp-dump/cpp-dump.hpp" #endif #include <chrono> #include <random> using namespace chrono; #define rep(i, n) for (ll i = 0; i < (int)(n); ++i) #define rep1(i, n) for (ll i = 1; i <= (n); ++i) #define rrep(i, n) for (ll i = n; i > 0; --i) #define bitrep(i, n) for (ll i = 0; i < (1 << n); ++i) #define all(a) (a).begin(), (a).end() #define yesNo(b) ((b) ? "Yes" : "No") using ll = long long; using ull = unsigned long long; using ld = long double; string alphabet = "abcdefghijklmnopqrstuvwxyz"; string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; constexpr double pi = 3.141592653589793; constexpr ll smallMOD = 998244353; constexpr ll bigMOD = 1000000007; constexpr ll INF = 1LL << 60; constexpr ll dx[] = {1, 0, -1, 0, 1, -1, -1, 1}; constexpr ll dy[] = {0, 1, 0, -1, 1, 1, -1, -1}; // init. struct Init { Init() { ios::sync_with_stdio(0); cin.tie(0); cout << fixed << setprecision(15); } } init; template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << "["; rep(i, vec.size()) { os << vec[i]; if (i != vec.size() - 1) os << ", "; } os << "]"; return os; } template <typename T> ostream &operator<<(ostream &os, const vector<vector<T>> &vec) { os << "["; rep(i, vec.size()) { os << vec[i]; if (i != vec.size() - 1) os << ", "; } os << "]"; return os; } template <typename T, typename U> ostream &operator<<(ostream &os, const pair<T, U> &pair_var) { os << "(" << pair_var.first << ", " << pair_var.second << ")"; return os; } template <typename T> ostream &operator<<(ostream &os, const set<T> &st) { os << "{"; for (auto itr = st.begin(); itr != st.end(); ++itr) { os << *itr; if (next(itr) != st.end()) os << ", "; } os << "}"; return os; } template <typename T> ostream &operator<<(ostream &os, const multiset<T> &st) { os << "{"; for (auto itr = st.begin(); itr != st.end(); ++itr) { os << *itr; if (next(itr) != st.end()) os << ", "; } os << "}"; return os; } template <typename T> ostream &operator<<(ostream &os, const queue<T> &que) { queue<T> que2 = que; os << "{"; while (!que2.empty()) { os << que2.front(); que2.pop(); if (!que2.empty()) os << ", "; } os << "}"; return os; } template <typename T> ostream &operator<<(ostream &os, const deque<T> &deq) { os << "{"; rep(i, deq.size()) { os << deq[i]; if (i != deq.size() - 1) os << ", "; } os << "}"; return os; } template <typename T, typename U> ostream &operator<<(ostream &os, const map<T, U> &mp) { os << "{"; for (auto itr = mp.begin(); itr != mp.end(); ++itr) { os << *itr; if (next(itr) != mp.end()) os << ", "; } os << "}"; return os; } template <typename T> ostream &operator<<(ostream &os, const stack<T> &stk) { stack<T> stk2 = stk; os << "{"; while (!stk2.empty()) { os << stk2.top(); stk2.pop(); if (!stk2.empty()) os << ", "; } os << "}"; return os; } template <typename T> ostream &operator<<(ostream &os, const priority_queue<T> &que) { priority_queue<T> que2 = que; os << "{"; while (!que2.empty()) { os << que2.top(); que2.pop(); if (!que2.empty()) os << ", "; } os << "}"; return os; } template <class T> bool chmax(T &a, T b) { if (a < b) { a = b; return 1; } return 0; } template <class T> bool chmin(T &a, T b) { if (b < a) { a = b; return 1; } return 0; } template <class T> size_t HashCombine(const size_t seed, const T &v) { return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } template <class T, class S> struct std::hash<std::pair<T, S>> { size_t operator()(const std::pair<T, S> &keyval) const noexcept { return HashCombine(std::hash<T>()(keyval.first), keyval.second); } }; template <class T> struct std::hash<std::vector<T>> { size_t operator()(const std::vector<T> &keyval) const noexcept { size_t s = 0; for (auto &&v : keyval) s = HashCombine(s, v); return s; } }; template <int N> struct HashTupleCore { template <class Tuple> size_t operator()(const Tuple &keyval) const noexcept { size_t s = HashTupleCore<N - 1>()(keyval); return HashCombine(s, std::get<N - 1>(keyval)); } }; template <> struct HashTupleCore<0> { template <class Tuple> size_t operator()(const Tuple &keyval) const noexcept { return 0; } }; template <class... Args> struct std::hash<std::tuple<Args...>> { size_t operator()(const tuple<Args...> &keyval) const noexcept { return HashTupleCore<tuple_size<tuple<Args...>>::value>()(keyval); } }; // Math. vector<ll> all_divisors(ll N) { vector<ll> res; for (ll i = 1; i * i <= N; ++i) { if (N % i != 0) continue; res.push_back(i); if (N / i != i) res.push_back(N / i); } sort(res.begin(), res.end()); return res; } void recursive_comb(vector<ll> indexes, ll s, ll rest, function<void(vector<ll>)> f) { if (rest == 0) { f(indexes); } else { if (s < 0) return; recursive_comb(indexes, s - 1, rest, f); indexes[rest - 1] = s; recursive_comb(indexes, s - 1, rest - 1, f); } } void foreach_comb(ll n, ll k, function<void(vector<ll>)> f) { vector<ll> indexes(k); recursive_comb(indexes, n - 1, k, f); } vector<pair<ll, ll>> prime_factorize(ll N) { vector<pair<ll, ll>> res; for (ll p = 2; p * p <= N; ++p) { if (N % p != 0) continue; ll e = 0; while (N % p == 0) { ++e; N /= p; } res.emplace_back(p, e); } if (N != 1) { res.emplace_back(N, 1); } return res; } ll repeated_squaring(ll x, ll y, ll z = smallMOD) { ll ans = 1; bitset<64> bits(y); string bit_str = bits.to_string(); reverse(all(bit_str)); rep(i, 64) { if (bit_str[i] == '1') ans = ans * x % z; x = x * x % z; } return ans; } // String. bool isPalindrome(string str) { ll low = 0; ll high = str.length() - 1; while (low < high) { if (str[low] != str[high]) { return false; } low++; high--; } return true; } map<char, ll> alphabetHash = { {'a', 2}, {'b', 3}, {'c', 5}, {'d', 7}, {'e', 11}, {'f', 13}, {'g', 17}, {'h', 19}, {'i', 23}, {'j', 29}, {'k', 31}, {'l', 37}, {'m', 41}, {'n', 43}, {'o', 47}, {'p', 53}, {'q', 59}, {'r', 61}, {'s', 67}, {'t', 71}, {'u', 73}, {'v', 79}, {'w', 83}, {'x', 89}, {'y', 97}, {'z', 101}, }; void split(vector<string> &elems, const string &s, char delim) { stringstream ss(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } } ll string_mod(string s, ll mod) { ll rest = 0; for (char c : s) { ll v = c - '0'; rest = (rest * 10 + v) % mod; } return rest; } // algorithms. pair<pair<ll, ll>, pair<ll, ll>> maxAndMinSubarraySum(const vector<ll> &nums) { ll maxSum = nums[0]; ll minSum = nums[0]; ll maxStart = 0; ll maxEnd = 0; ll minStart = 0; ll minEnd = 0; ll currentMaxSum = nums[0]; ll currentMinSum = nums[0]; ll tempMaxStart = 0; ll tempMinStart = 0; for (ll i = 1; i < nums.size(); ++i) { if (currentMaxSum < 0) { currentMaxSum = nums[i]; tempMaxStart = i; } else { currentMaxSum += nums[i]; } if (currentMaxSum > maxSum) { maxSum = currentMaxSum; maxStart = tempMaxStart; maxEnd = i; } if (currentMinSum > 0) { currentMinSum = nums[i]; tempMinStart = i; } else { currentMinSum += nums[i]; } if (currentMinSum < minSum) { minSum = currentMinSum; minStart = tempMinStart; minEnd = i; } } return make_pair(make_pair(maxStart, maxEnd), make_pair(minStart, minEnd)); } // array. vector<string> RotateVectorString(vector<string> A, bool clockwise = false, char leading = 0) { ll N = A.size(); if (N == 0) return A; ll M = 0; rep(i, N) { M = max(M, (ll)A[i].size()); } vector<string> B(M, string(N, leading)); rep(i, N) { rep(j, A[i].size()) { if (clockwise) { B[j][N - 1 - i] = A[i][j]; } else { B[M - 1 - j][i] = A[i][j]; } } } return B; } // struct. // Data structure. struct CumulativeSum2D { vector<vector<ll>> data; CumulativeSum2D(vector<vector<ll>> &source) { ll h = source.size(); ll w = 0; if (h != 0) w = source[0].size(); data.resize(h + 1, vector<ll>(w + 1, 0)); rep(i, h) { rep(j, w) { data[i + 1][j + 1] = source[i][j]; } } rep(i, h + 1) { rep(j, w) { data[i][j + 1] += data[i][j]; } } rep(i, h) { rep(j, w + 1) { data[i + 1][j] += data[i][j]; } } } ll query(ll x1, ll y1, ll x2, ll y2) { return data[x2][y2] - data[x1][y2] - data[x2][y1] + data[x1][y1]; } }; struct CumulativeSumND { public: vector<ll> sum; ll N; ll d; CumulativeSumND(ll d, ll N, vector<ll> &data) { this->d = d; this->N = N; ll cumSize = 1; ll size = 1; ll bitSize = 1; for (ll i = 0; i < d; i++) { cumSize *= N + 1; size *= N; bitSize *= 2; assert(cumSize <= 1e8); assert(size <= 1e8); assert(bitSize <= 1e8); } assert(data.size() == size); sum.resize(cumSize); build(data); } // (X1,Y1,Z1,W1,...,X2,Y2,Z2,W2,...) ll query(vector<ll> q) { assert(q.size() == d * 2); vector<ll> LPos(d + 1, 0); vector<ll> RPos(d + 1, 0); ll res = 0; for (ll i = 0; i < d; i++) { LPos[i + 1] = q[i] - 1; RPos[i + 1] = q[i + d]; } bitrep(i, d) { vector<ll> pos(d + 1, 0); ll cnt = 0; rep(j, d) { if (i & (1 << j)) { pos[j + 1] = RPos[j + 1]; } else { pos[j + 1] = LPos[j + 1]; cnt++; } } if (cnt % 2) { res -= sum[getPos(pos, 1)]; } else { res += sum[getPos(pos, 1)]; } } return res; } private: // 0-indexed. ll getPos(vector<ll> &pos, bool isZeroIndex) { assert(pos.size() == d + 1); vector<ll> A(d, 1); for (ll i = 0; i < d - 1; i++) { A[i + 1] = A[i] * (N + isZeroIndex); } reverse(all(A)); ll res = 0; for (ll i = 1; i < d + 1; i++) { res += A[i - 1] * pos[i]; } return res; } void build(vector<ll> &data) { { // 0-indexed→1-indexed. vector<ll> loop(d + 1, 0); while (loop[0] != 1) { bool isZero = false; for (ll i = 1; i < d + 1; i++) { if (loop[i] == 0) { isZero = true; break; } } if (!isZero) { ll sumPos = getPos(loop, 1); for (ll i = 1; i < d + 1; i++) { loop[i]--; } ll dataPos = getPos(loop, 0); for (ll i = 1; i < d + 1; i++) { loop[i]++; } sum[sumPos] = data[dataPos]; } loop[d]++; // 繰り上がり処理. for (ll i = d; i > 0; i--) { if (loop[i] == N + 1) { loop[i] = 0; loop[i - 1]++; } } } } // calc sum. { vector<ll> loop(d + 1, 0); while (loop[0] != d) { ll p1 = getPos(loop, 1); loop[loop[0] + 1]++; ll p2 = getPos(loop, 1); sum[p2] += sum[p1]; loop[loop[0] + 1]--; loop[d]++; // 繰り上がり処理. for (ll i = d; i > 0; i--) { if (i == loop[0] + 1) { // N-1回. if (loop[i] == N) { loop[i] = 0; loop[i - 1]++; } } else { // N回. if (loop[i] == N + 1) { loop[i] = 0; loop[i - 1]++; } } } } } } }; struct BitVector { public: vector<int> data, cum; BitVector(vector<int> &source) { if (source.size() != 0) { data.resize(source.size(), 0); cum.resize(source.size(), 0); cum[0] = source[0]; for (int i = 0; i < (int)source.size(); i++) { data[i] = source[i]; assert(source[i] == 0 || source[i] == 1); if (i != 0) { cum[i] = cum[i - 1] + source[i]; } } } } int size() { return (int)data.size(); } int get(int i) { return data[i]; } int rank1(int i) { if (i <= 0) { return 0; } i = min(i, (int)data.size()); return cum[i - 1]; } int rank0(int i) { if (i <= 0) { return 0; } i = min(i, (int)data.size()); return i - rank1(i); } int rank0_all() { return rank0(data.size()); } int rank1_all() { return rank1(data.size()); } int select0(int k) { // K個目の0のindexを返す. if (k <= 0 || k > rank0_all()) { return -1; } int l = 0, r = data.size(); while (r - l > 1) { int mid = (l + r) / 2; if (rank0(mid) < k) { l = mid; } else { r = mid; } } return l; } int select1(int k) { // K個目の1のindexを返す. if (k <= 0 || k > rank1_all()) { return -1; } int l = 0, r = data.size(); while (r - l > 1) { int mid = (l + r) / 2; if (rank1(mid) < k) { l = mid; } else { r = mid; } } return l; } }; struct UnionFind { vector<ll> parent; vector<ll> parentSize; vector<set<ll>> children; UnionFind(ll N) { rep(i, N + 1) { parent.push_back(i); parentSize.push_back(1); children.push_back({i}); } } ll root(ll x) { if (parent[x] == x) return x; parent[x] = root(parent[x]); return parent[x]; } void unite(ll x, ll y) { x = root(x); y = root(y); if (x == y) return; if (parentSize[x] <= parentSize[y]) { parent[x] = y; parentSize[y] += parentSize[x]; for (auto c : children[x]) { children[y].insert(c); } children[x].clear(); } else { parent[y] = x; parentSize[x] += parentSize[y]; for (auto c : children[y]) { children[x].insert(c); } children[y].clear(); } } bool same(ll x, ll y) { return root(x) == root(y); } ll size(ll x) { return parentSize[root(x)]; } }; // Math. struct NCR { ll max = 510000, mod = 0; vector<ll> fact, inv, inv_fact; NCR(ll mod = 998244353) { this->mod = mod; fact.resize(max); inv.resize(max); inv_fact.resize(max); fact[0] = 1; fact[1] = 1; inv[0] = 1; inv[1] = 1; inv_fact[0] = 1; inv_fact[1] = 1; for (ll i = 2; i < max; i++) { fact[i] = fact[i - 1] * i % mod; inv[i] = mod - inv[mod % i] * (mod / i) % mod; inv_fact[i] = inv_fact[i - 1] * inv[i] % mod; } } ll nCr(ll n, ll r) { ll x = fact[n]; ll y = inv_fact[n - r]; ll z = inv_fact[r]; if (n < r) return 0; if (n < 0 || r < 0) return 0; return x * ((y * z) % mod) % mod; } }; // Graph. struct Edge { ll to; ll cost; Edge(ll to, ll cost) : to(to), cost(cost) {} bool operator>(const Edge &e) const { return cost > e.cost; } }; struct Graph { vector<vector<Edge>> g; Graph(ll n) { g.resize(n); } ll size() { return g.size(); } void add_edge(ll from, ll to, ll cost = 1) { g[from].push_back(Edge(to, cost)); g[to].push_back(Edge(from, cost)); } void add_directed_edge(ll from, ll to, ll cost = 1) { g[from].push_back(Edge(to, cost)); } pair<ll, vector<ll>> tree_diameter() { function<pair<ll, ll>(ll, ll)> dfs = [&](ll v, ll p) -> pair<ll, ll> { pair<ll, ll> res = {0, v}; for (auto e : g[v]) { if (e.to == p) continue; auto [d, u] = dfs(e.to, v); d += e.cost; if (res.first < d) { res.first = d; res.second = u; } } return res; }; auto [d, u] = dfs(0, -1); auto [d2, v] = dfs(u, -1); vector<ll> path; function<void(ll, ll, ll)> get_path = [&](ll v, ll p, ll u) { if (v == u) { path.push_back(v); return; } for (auto e : g[v]) { if (e.to == p) continue; get_path(e.to, v, u); if (!path.empty()) { path.push_back(v); return; } } }; get_path(u, -1, v); return {d2, path}; } vector<Edge> &operator[](ll v) { return g[v]; } }; struct Dijkstra { vector<ll> dist; vector<ll> prev; // dijkstraを構築 Dijkstra(Graph &g, ll s) { ll n = g.size(); dist.assign(n, INF); prev.assign(n, -1); priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> pq; dist[s] = 0; pq.emplace(dist[s], s); while (!pq.empty()) { auto p = pq.top(); pq.pop(); ll v = p.second; if (dist[v] < p.first) continue; for (auto &e : g[v]) { if (dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist[v] + e.cost; prev[e.to] = v; pq.emplace(dist[e.to], e.to); } } } } // 最小コストを求める ll get_cost(ll to) { return dist[to]; } // 最短経路を求める vector<ll> get_path(ll to) { vector<ll> get_path; for (ll i = to; i != -1; i = prev[i]) { get_path.push_back(i); } reverse(get_path.begin(), get_path.end()); return get_path; } // 到達可能か調べる bool cango(ll to) { return (dist[to] != INF); } }; struct Bellman_ford { vector<ll> dist; vector<ll> prev; ll start; ll size; bool cl = false; // bellman_fordを構築 Bellman_ford(Graph &g, ll s) { start = s; ll n = g.size(); size = n; dist.assign(n, INF); prev.assign(n, -1); vector<ll> counts(n); vector<bool> inqueue(n); queue<ll> q; dist[s] = 0; q.push(s); inqueue[s] = true; while (!q.empty()) { ll from = q.front(); q.pop(); inqueue[from] = false; for (auto &e : g[from]) { ll d = dist[from] + e.cost; if (d < dist[e.to]) { dist[e.to] = d; prev[e.to] = from; if (!inqueue[e.to]) { q.push(e.to); inqueue[e.to] = true; ++counts[e.to]; if (n < counts[e.to]) cl = true; } } } } } // 最小コストを求める ll get_cost(ll to) { return dist[to]; } // 最短経路を求める vector<ll> get_path(ll to) { vector<ll> path; if (dist[to] != INF) { for (ll i = to; i != -1; i = prev[i]) { path.push_back(i); } reverse(path.begin(), path.end()); } return path; } // 到達可能か調べる bool cango(ll to) { return (dist[to] != INF); } // 閉路の有無を調べる bool closed() { return cl; } }; struct Warshall_floyd { vector<vector<ll>> d; vector<vector<ll>> next; bool cl = false; // warshall_floydを構築 Warshall_floyd(Graph &g) { ll n = g.size(); d.resize(n, vector<ll>(n, INF)); next.resize(n, vector<ll>(n, -1)); for (ll i = 0; i < n; i++) { d[i][i] = 0; } for (ll i = 0; i < n; i++) { for (auto e : g[i]) { d[i][e.to] = e.cost; next[i][e.to] = e.to; } } for (ll k = 0; k < n; ++k) { for (ll i = 0; i < n; ++i) { for (ll j = 0; j < n; ++j) { if (d[i][j] > d[i][k] + d[k][j]) { d[i][j] = d[i][k] + d[k][j]; next[i][j] = next[i][k]; } } } } for (ll i = 0; i < n; i++) { if (d[i][i] < 0) { cl = true; break; } } } // 最小コストを求める ll get_cost(ll from, ll to) { return d[from][to]; } // 最短経路を求める vector<ll> get_path(ll from, ll to) { if (d[from][to] == INF) return {}; vector<ll> path; for (ll at = from; at != to; at = next[at][to]) { if (at == -1) return {}; path.push_back(at); } path.push_back(to); return path; } // 到達可能か調べる bool cango(ll from, ll to) { return d[from][to] != INF; } // 負の閉路の有無を調べる bool closed() { return cl; } }; // String. struct Suffix_array { vector<ll> sa, rank, tmp; ll n; string base; // suffix_arrayを構築 Suffix_array(const string s) { n = s.size(); base = s; sa.resize(n); rank.resize(n); tmp.resize(n); for (ll i = 0; i < n; i++) { sa[i] = i; rank[i] = s[i]; } for (ll k = 1; k < n; k *= 2) { auto compare_sa = [&](ll i, ll j) { if (rank[i] != rank[j]) return rank[i] < rank[j]; ll ri = (i + k < n) ? rank[i + k] : -1; ll rj = (j + k < n) ? rank[j + k] : -1; return ri < rj; }; sort(sa.begin(), sa.end(), compare_sa); tmp[sa[0]] = 0; for (ll i = 1; i < n; i++) { tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0); } rank = tmp; } } // 部分文字列の個数を求める ll get_counts(string t) { string u = t + "彁"; ll num1, num2; { ll m = t.size(); ll ng = -1, ok = n; while (ok - ng > 1) { ll mid = (ng + ok) / 2; ll l = sa[mid]; if (base.substr(l, m) >= t) { ok = mid; } else { ng = mid; } } num1 = ok; } { ll m = u.size(); ll ng = -1, ok = n; while (ok - ng > 1) { ll mid = (ng + ok) / 2; ll l = sa[mid]; if (base.substr(l, m) >= u) { ok = mid; } else { ng = mid; } } num2 = ok; } return num2 - num1; } // make lcp array vector<ll> make_lcp() { vector<ll> lcp(n); for (ll i = 0; i < n; i++) { rank[sa[i]] = i; } ll h = 0; lcp[0] = 0; for (ll i = 0; i < n; i++) { if (rank[i] == n - 1) { h = 0; continue; } ll j = sa[rank[i] + 1]; while (i + h < n && j + h < n && base[i + h] == base[j + h]) { h++; } lcp[rank[i]] = h; if (h > 0) { h--; } } return lcp; } }; // others. class Timer { public: Timer(ll ms) : duration(ms), start_time(steady_clock::now()) {} bool isTimeOver() const { auto current_time = steady_clock::now(); auto elapsed = duration_cast<milliseconds>(current_time - start_time).count(); return elapsed >= duration; } private: ll duration; steady_clock::time_point start_time; }; class FunctionalGraph { private: const ll V; ll loop_id; vector<ll> nx; void make_loop(const ll st, ll nw, vector<ll> &vec) { while (nx[nw] != st) { vec.push_back(nx[nw]); visit[nx[nw]] = loop_id; nw = nx[nw]; } } ll dfs(ll u, vector<ll> &vec) { visit[u] = -loop_id; ll v = nx[u]; if (visit[v] == -loop_id) { vec.push_back(u), vec.push_back(v); visit[u] = visit[v] = loop_id; make_loop(u, v, vec); loop_id++; return 0; } else if (visit[v] == 0) { const ll res = dfs(v, vec); if (res == 0) return 0; else return visit[u] = res; } return visit[u] = (visit[v] > 0 ? -visit[v] : visit[v]); } void make_graph() { graph.resize(V); for (ll i = 0; i < V; i++) { if (visit[i] < 0) graph[nx[i]].push_back(i); } } public: vector<ll> visit; vector<vector<ll>> loop, graph; FunctionalGraph(const ll node_size) : V(node_size), loop_id(1), nx(V, 0), visit(V, 0) {} void add_edge(ll u, ll v) { nx[u] = v; if (u == nx[u]) visit[u] = loop_id++, loop.push_back({u}); } void solve() { for (ll i = 0; i < V; i++) { if (visit[i] == 0) { vector<ll> vec; dfs(i, vec); if (!vec.empty()) loop.push_back(move(vec)); } } } }; void print2DArr(vector<vector<ll>> &arr) { for (auto &a : arr) { for (auto &b : a) { cout << b << " "; } cout << endl; } cout << endl; } string encode(ll n) { string res = ""; while (n) { n--; res = ALPHABET[n % 26] + res; n /= 26; } return res; } ll decode(string s) { ll res = 0; for (char c : s) { res = res * 26 + c - 'A' + 1; } return res; } ll digit_sum(ll n) { ll sum = 0; while (n > 0) { sum += n % 10; n /= 10; } return sum; } ll non_mod_ncr(ll n, ll r) { ll res = 1; for (ll i = 0; i < r; i++) { res *= (n - i); } for (ll i = 0; i < r; i++) { res /= (i + 1); } return res; } int rand_int(int a, int b) { return a + rand() % (b - a + 1); } int main() { string s; cin >> s; vector<ll> cnt(26, 0); rep(i, s.size()) cnt[s[i] - 'a']++; string Y = "yukari"; string A = "akari"; string X = "yuzukizu"; vector<ll> cntY(26, 0), cntA(26, 0), cntX(26, 0); rep(i, Y.size()) cntY[Y[i] - 'a']++; rep(i, A.size()) cntA[A[i] - 'a']++; rep(i, X.size()) cntX[X[i] - 'a']++; ll ansY = INF; rep(i, 26) { if (cntY[i] == 0) continue; chmin(ansY, cnt[i] / cntY[i]); } ll ansA = INF; rep(i, 26) { if (cntA[i] == 0) continue; chmin(ansA, cnt[i] / cntA[i]); } ll ansX = INF; rep(i, 26) { if (cntX[i] == 0) continue; chmin(ansX, cnt[i] / cntX[i]); } cout << ansY << " " << ansA << " " << ansX << endl; return 0; }