A. Souvlaki VS. Kalamaki
题意:一个数组\(a\),你可以将它重排。然后从左到右操作,奇数位置你操作,偶数位置另一个人操作。每次可以选择交换\(a_i, a_{i+1}\)或者不操作。你想使得数组升序,另一个不想。求能不能使得数组升序。
考虑排序后的\(a\),对于每个偶数位置\(i\),如果\(a_i \ne a_{i+1}\),则后手总有办法使得\(a_i > a_{i+1}\)。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::ranges::sort(a);for (int i = 1; i + 1 < n; i += 2) {if (a[i] != a[i + 1]) {std::cout << "NO\n";return;}}std::cout << "YES\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
B. Siga ta Kymata
题意:开始有一个全\(0\)的\(01\)串\(s\),以及一个排列。你想把\(s\)变换,使得对于另一个给出的\(01\)串\(x\),满足\(x_i = 1\)的地方\(s_i = 1\),\(x_i = 0\)的地方没有要求。每次操作可以选择\(l, r\),对于\(i \in [l, r]\)且\(\min(p_l, p_r) < p_i < \max(p_l, p_r)\)的每个\(i\)使得\(s_i = 1\)。最多\(5\)次操作,求方案。
观察到第一个位置和最后一个位置不可能被覆盖,且对于\(p_i = 1, p_i = n\)的位置,我们也无法覆盖。所以如果这些位置是\(1\)则无解。
否则记\(pos_1, pos_n\)为\(1, n\)在排列里的位置。
给出\([1, pos_1], [1, pos_n], [pos_1, n], [pos_n, n], [\min(pos_1, pos_n), \max(pos_1, pos_n)]\)\(5\)个操作就一定能使得其它位置变成\(1\)。
因为对于\((1, \min(pos_1, pos_n))\)这些位置,都变成了\(1\),对于\((\max(pos_1, pos_n), n)\)这些位置,也都变成了\(1\)。最后对于\((pos_1, pos_n)\)之间的位置,也会变成\(1\)。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> p(n);for (int i = 0; i < n; ++ i) {std::cin >> p[i];}std::string s;std::cin >> s;for (int i = 0; i < n; ++ i) {if (s[i] == '1') {if (i == 0 || i == n - 1 || p[i] == 1 || p[i] == n) {std::cout << -1 << "\n";return;}}}int p1 = std::ranges::find(p, 1) - p.begin() + 1;int pn = std::ranges::find(p, n) - p.begin() + 1;if (p1 > pn) {std::swap(p1, pn);}std::cout << 5 << "\n";std::cout << 1 << " " << p1 << "\n";std::cout << 1 << " " << pn << "\n";std::cout << p1 << " " << n << "\n";std::cout << pn << " " << n << "\n";std::cout << p1 << " " << pn << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
C. Monopati
题意:一个\(2\times n\)的矩阵,每个位置都有一个\([1, 2n]\)之间的元素,你从\((1, 1)\)出发,每次可以向右或者向下走。求有多少\([l, r]\)满足\(1\leq l \leq r \leq 2n\)且如果只使用\([l, r]\)之间的数可以从\((1, 1)\)走到\((2, n)\)。
只有一次向下的机会,记在\(k\)列向下,那么走过的位置就是\(a_{1, 1}, a_{1,2}, ..., a_{1, k}\)和\(a_{2, k}, a_{2, k+1}, ..., a_{2, n}\)。那么\([l, r]\)需要包含其中的最小值和最大值。
则可以预处理第一行的前缀最小最大值和第二行的后缀最小最大值。记每个\(k\)对于的区间为\([l_k, r_k]\),那么对于\(l \leq l_k, r_k \leq r\)的区间就是可行的。
可以记录每个\(r\)对应的最大的\(l\),那么比它大的\(r\)最大也能取到它的\(r\)。取一下前缀\(max\)就可以知道每个\(r\)可以选多少\(l\)。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> a1(n + 1), a2(n + 1);for (int i = 1; i <= n; ++ i) {std::cin >> a1[i];}for (int i = 1; i <= n; ++ i) {std::cin >> a2[i];}constexpr int inf = 1e9;std::vector<int> pre_min(n + 1), pre_max(n + 1);pre_min[0] = inf;pre_max[0] = -inf;for (int i = 1; i <= n; ++ i) {pre_min[i] = std::min(pre_min[i - 1], a1[i]);pre_max[i] = std::max(pre_max[i - 1], a1[i]);}std::vector<int> suf_min(n + 2), suf_max(n + 2);suf_min[n + 1] = inf;suf_max[n + 1] = -inf;for (int i = n; i >= 1; -- i) {suf_min[i] = std::min(suf_min[i + 1], a2[i]);suf_max[i] = std::max(suf_max[i + 1], a2[i]);}std::vector<int> R(2 * n + 1);for (int i = 1; i <= n; ++ i) {int l = std::min(pre_min[i], suf_min[i]);int r = std::max(pre_max[i], suf_max[i]);R[r] = std::max(R[r], l);}i64 ans = 0;for (int i = 1; i <= 2 * n; ++ i) {R[i] = std::max(R[i], R[i - 1]);ans += R[i];}std::cout << ans << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
D1. Diadrash (Easy Version)
题意:交互题。有一个隐藏的\([0, n - 1]\)的排列,和\(q\)个区间。你需要确定哪个区间的\(mex\)最大。你最多可以询问\(\max(300, \lceil \frac{n}{2} \rceil + 2)\)次。每次问一个区间的\(mex\)。
考虑二分\(mex\),求有没有区间的\(mex \geq mid\)。那么需要满足这个区间至少包含\([0, mid - 1]\)的每个数。
则可以在\(check\)里继续二分,求\([0, mid - 1]\)出现最左的前缀,和\([0, mid - 1]\)出现最右的后缀。那么可以得到\([0, mid - 1]\)这些数的左右区间,检查有没有一个区间包含这个区间。
那么总共询问\(2log_n^2\)次。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;int ask(int l, int r) {std::cout << "? " << l << " " << r << std::endl;int res;std::cin >> res;return res;
}void solve() {int n, q;std::cin >> n >> q;std::vector<std::pair<int, int>> Q(q);for (int i = 0; i < q; ++ i) {std::cin >> Q[i].first >> Q[i].second;}auto check = [&](int k) -> bool {int lo = 1, hi = n;while (lo < hi) {int mid = lo + hi >> 1;if (ask(1, mid) >= k) {hi = mid;} else {lo = mid + 1;}}int R = lo;lo = 1, hi = n;while (lo < hi) {int mid = lo + hi + 1 >> 1;if (ask(mid, n) >= k) {lo = mid;} else {hi = mid - 1;}}int L = lo;for (auto & [l, r] : Q) {if (l <= L && R <= r) {return true;}}return false;};int lo = 0, hi = n;while (lo < hi) {int mid = lo + hi + 1 >> 1;if (check(mid)) {lo = mid;} else {hi = mid - 1;}}std::cout << "! " << lo << std::endl;
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}