Submission #1176282

#TimeUsernameProblemLanguageResultExecution timeMemory
1176282KanonHieroglyphs (IOI24_hieroglyphs)C++20
100 / 100
205 ms28256 KiB
#include <bits/stdc++.h> #include "hieroglyphs.h" using namespace std; class segtree { public: struct node { int min_val = INT_MAX; void apply(int l, int r, int v) { min_val = v; } }; node unite(const node &a, const node &b) const { node res; res.min_val = min(a.min_val, b.min_val); return res; } inline void push(int x, int l, int r) { } inline void pull(int x, int z) { tree[x] = unite(tree[x + 1], tree[z]); } int n; vector<node> tree; void build(int x, int l, int r) { if (l == r) { return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); build(x + 1, l, y); build(z, y + 1, r); pull(x, z); } template <typename M, typename... T> void build(int x, int l, int r, const vector<M> &v, const T&... t) { if (l == r) { tree[x].apply(l, r, v[l], t...); return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); build(x + 1, l, y, v, t...); build(z, y + 1, r, v, t...); pull(x, z); } template <typename M, typename... T> segtree(const vector<M> &v, const T&... t) { n = v.size(); assert(n > 0); tree.resize(2 * n - 1); build(0, 0, n - 1, v, t...); } segtree(int _n) : n(_n) { assert(n > 0); tree.resize(2 * n - 1); build(0, 0, n - 1); } segtree(){}; node get(int x, int l, int r, int ll, int rr) { if (ll <= l && r <= rr) { return tree[x]; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); push(x, l, r); node res{}; if (rr <= y) { res = get(x + 1, l, y, ll, rr); } else { if (ll > y) { res = get(z, y + 1, r, ll, rr); } else { res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr)); } } pull(x, z); return res; } node get(int ll, int rr) { assert(0 <= ll && ll <= rr && rr <= n - 1); return get(0, 0, n - 1, ll, rr); } node get(int p) { assert(0 <= p && p <= n - 1); return get(0, 0, n - 1, p, p); } template <typename... M> void modify(int x, int l, int r, int ll, int rr, const M&... v) { if (ll <= l && r <= rr) { tree[x].apply(l, r, v...); return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); push(x, l, r); if (ll <= y) { modify(x + 1, l, y, ll, rr, v...); } if (rr > y) { modify(z, y + 1, r, ll, rr, v...); } pull(x, z); } template <typename... M> void modify(int ll, int rr, const M&... v) { assert(0 <= ll && ll <= rr && rr <= n - 1); modify(0, 0, n - 1, ll, rr, v...); } }; vector<int> ucs (vector<int> a, vector<int> b) { int n = a.size(); int m = b.size(); int Total_number = max(*max_element(a.begin(), a.end()), *max_element(b.begin(), b.end())) + 1; vector<vector<int>> A_postions_of_num(Total_number, vector<int>(1, -1)); vector<vector<int>> B_postions_of_num(Total_number, vector<int>(1, -1)); for (int i = 0; i < n; i++) { A_postions_of_num[a[i]].push_back(i); } for (int i = 0; i < m; i++) { B_postions_of_num[b[i]].push_back(i); } for (int i = 0; i < Total_number; i++) { A_postions_of_num[i].push_back(n); B_postions_of_num[i].push_back(m); } auto Nearest_next_B = [&](int pos, int val, int dir) { if (pos == m && dir == +1) return m; if (pos == -1 && dir == -1) return -1; auto it = lower_bound(B_postions_of_num[val].begin(), B_postions_of_num[val].end(), pos); if (dir == +1) { assert(it != B_postions_of_num[val].end()); if (*it == pos) { assert(next(it) != B_postions_of_num[val].end()); it++; return *it; } else { return *it; } } else { assert(it != B_postions_of_num[val].begin()); it--; return *it; } }; auto Nearest_next_A = [&](int pos, int val, int dir) { if (pos == n && dir == +1) return n; if (pos == -1 && dir == -1) return -1; auto it = lower_bound(A_postions_of_num[val].begin(), A_postions_of_num[val].end(), pos); if (dir == +1) { assert(it != A_postions_of_num[val].end()); if (*it == pos) { assert(next(it) != A_postions_of_num[val].end()); it++; return *it; } else { return *it; } } else { assert(it != A_postions_of_num[val].begin()); it--; return *it; } }; vector<int> Left_most_reached_in_B_of_A(n, m); vector<int> Left_most_reached_in_A_of_B(m, n); for (int rot = 0; rot < 2; rot++) { segtree Left_B_reached_from_a(n); for (int pos_a = 0; pos_a < n; pos_a++) { int prev_a_same_val = Nearest_next_A(pos_a, a[pos_a], -1); int prev_b_reached = prev_a_same_val == -1 ? -1 : Left_B_reached_from_a.get(prev_a_same_val).min_val; if (prev_a_same_val < pos_a - 1) { prev_b_reached = min(prev_b_reached, Left_B_reached_from_a.get(prev_a_same_val + 1, pos_a - 1).min_val); } int cur_b_reached = Nearest_next_B(prev_b_reached, a[pos_a], +1); Left_B_reached_from_a.modify(pos_a, pos_a, cur_b_reached); Left_most_reached_in_B_of_A[pos_a] = cur_b_reached; } swap(n, m); swap(a, b); swap(Left_most_reached_in_B_of_A, Left_most_reached_in_A_of_B); swap(A_postions_of_num, B_postions_of_num); } vector<bool> A_must(n); vector<bool> B_must(m); bool matched = true; for (int num = 0; num < Total_number; num++) { int A_num_sz = A_postions_of_num[num].size(); int B_num_sz = B_postions_of_num[num].size(); if (A_num_sz >= B_num_sz) { int cnt = 0; int B_pos_last_matched = m; for (int a_pos_id = A_num_sz - 2; a_pos_id >= 1; a_pos_id--) { int a_pos = A_postions_of_num[num][a_pos_id]; assert(a[a_pos] == num); int b_far_pos = Left_most_reached_in_B_of_A[a_pos]; if (b_far_pos >= B_pos_last_matched) continue; int next_B_match = Nearest_next_B(B_pos_last_matched, num, -1); B_pos_last_matched = next_B_match; A_must[a_pos] = true; cnt++; } if (cnt != B_num_sz - 2) { matched = false; break; } } if (B_num_sz >= A_num_sz) { int cnt = 0; int A_pos_last_matched = n; for (int b_pos_id = B_num_sz - 2; b_pos_id >= 1; b_pos_id--) { int b_pos = B_postions_of_num[num][b_pos_id]; assert(b[b_pos] == num); int a_far_pos = Left_most_reached_in_A_of_B[b_pos]; if (a_far_pos >= A_pos_last_matched) continue; int next_A_match = Nearest_next_A(A_pos_last_matched, num, -1); A_pos_last_matched = next_A_match; B_must[b_pos] = true; cnt++; } if (cnt != A_num_sz - 2) { matched = false; break; } } if (A_num_sz < B_num_sz) for (int i : A_postions_of_num[num]) if (i > -1 && i < n) A_must[i] = true; if (B_num_sz < A_num_sz) for (int i : B_postions_of_num[num]) if (i > -1 && i < m) B_must[i] = true; } if (!matched) { return (vector<int>) {-1}; } vector<int> A_ret_pos = {-1}; vector<int> B_ret_pos = {-1}; for (int i = 0; i < n; i++) if (A_must[i]) A_ret_pos.push_back(i); for (int i = 0; i < m; i++) if (B_must[i]) B_ret_pos.push_back(i); A_ret_pos.push_back(n); B_ret_pos.push_back(m); assert(A_ret_pos.size() == B_ret_pos.size()); int sz = A_ret_pos.size(); for (int i = 1; i < sz - 1; i++) if (a[A_ret_pos[i]] != b[B_ret_pos[i]]) return (vector<int>) {-1}; vector<int> id_in_A_ret(n); vector<int> id_in_B_ret(m); for (int i = 0; i < n; i++) { id_in_A_ret[i] = A_must[i]; if (i > 0) id_in_A_ret[i] += id_in_A_ret[i - 1]; } for (int i = 0; i < m; i++) { id_in_B_ret[i] = B_must[i]; if (i > 0) id_in_B_ret[i] += id_in_B_ret[i - 1]; } for (int a_pos = 0; a_pos < n; a_pos++) { if (A_must[a_pos]) continue; int b_left_pos = Left_most_reached_in_B_of_A[a_pos]; assert(b_left_pos > -1); if (b_left_pos >= m) continue; if (id_in_A_ret[a_pos] > id_in_B_ret[b_left_pos]) return (vector<int>) {-1}; } for (int b_pos = 0; b_pos < m; b_pos++) { if (B_must[b_pos]) continue; int a_left_pos = Left_most_reached_in_A_of_B[b_pos]; assert(a_left_pos > -1); if (a_left_pos >= n) continue; if (id_in_B_ret[b_pos] > id_in_A_ret[a_left_pos]) return (vector<int>) {-1}; } vector<int> ret; for (int i : A_ret_pos) if (i > -1 && i < n) ret.push_back(a[i]); return ret; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...