A. Beautiful Average
点击查看代码
#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];}int ans = 0;for (int i = 0; i < n; ++ i) {int sum = 0, cnt = 0;for (int j = i; j < n; ++ j) {sum += a[j];++ cnt;ans = std::max(ans, sum / cnt);}}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;
}#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];}int ans = 0;for (int i = 0; i < n; ++ i) {int sum = 0, cnt = 0;for (int j = i; j < n; ++ j) {sum += a[j];++ cnt;ans = std::max(ans, sum / cnt);}}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;
}
B. Beautiful String
题意:一个\(01\)串,选一些位置出来,使得选出来的非递减,没选的组成一个回文。
把\(0\)都选上或者把\(1\)都选上。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::string s;std::cin >> s;std::vector<int> ans;for (int i = 0; i < n; ++ i) {if (s[i] == '0') {ans.push_back(i);}}std::cout << ans.size() << "\n";for (auto & x : ans) {std::cout << x + 1 << " \n"[x == ans.back()];}
}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. Beautiful XOR
题意:给你\(a, b\),每次使得\(a\)异或一个小于等于\(a\)的数,最后使得\(a\)变成\(b\)。
如果\(b\)的最高位大于\(a\)的最高位,则无解。
否则按位考虑就行,如果这一位\(a, b\)不同,则这一位异或一个\(1\)。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int a, b;std::cin >> a >> b;std::vector<int> ans;for (int i = 0; (1 << i) <= a; ++ i) {if ((a >> i & 1) != (b >> i & 1)) {ans.push_back(1 << i);a ^= 1 << i;}}if (a != b) {std::cout << -1 << "\n";} else {std::cout << ans.size() << "\n";for (auto & x : ans) {std::cout << x << " \n"[x == ans.back()];}}
}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;
}
D. Beautiful Permutation
题意:交互题。一个排列,把一个区间都加上了\(1\)。求这个区间。你可以询问原排列一个区间的和或者操作后的排列的一个区间的和。最多\(40\)次。
考虑分治,先求\([1, n]\)操作前和操作后的值,就可以知道这个区间有多长。然后每次询问左半边,如果左半边被操作过,看被操作的区间有多长,如果都在左半边则递归左半边,否则就可以知道这个区间横跨左右两边,然后因为知道了左边有长,于是就知道了区间的左右端点。否则左边没被操作 过则递归右边。询问\(2log_n\)次。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;i64 ask(int t, int l, int r) {std::cout << t << " " << l << " " << r << std::endl;i64 res;std::cin >> res;return res;
}void solve() {int n;std::cin >> n;i64 len = ask(2, 1, n) - ask(1, 1, n);std::vector<int> a;auto dfs = [&](auto && self, int l, int r) -> void {if (l == r) {a.push_back(l);return;}int mid = l + r >> 1;i64 v1 = ask(1, l, mid), v2 = ask(2, l, mid);if (v1 == v2) {self(self, mid + 1, r);} else if (v2 - v1 < len) {a.push_back(mid - (v2 - v1) + 1);a.push_back(mid + len - (v2 - v1));return;} else {self(self, l, mid);}};dfs(dfs, 1, n);std::ranges::sort(a);std::cout << "! " << a[0] << " " << a.back() << 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;
}
E. Beautiful Palindromes
题意:一个长度为\(n\)值域为\([1, n]\)的数组,你要操作\(k\)次,每次在末尾加上\([1, n]\)的某个数。最后使得整个数组的回文子数组最少。
记录每个数最后出现位置的值,没出现过的记为\(-1\)。那么每次拿最后出现位置最前的放最后面。线段树维护一下就行了。
证明就是如果选的数没有出现过,显然不会多回文数组。如果选的数出现过,那么要构成回文当前位置要和这个数最后出现的位置构成回文数组的两端,那么意味这中间的数构成了回文,如果一开始有数没有出现过,那么我们每次都没有构成回文,所以中间的数不会是回文;如果是一开始所有数就出现过了,那么因为数组长度为\(n\),则每个数恰好出现一次,则第一步会把\(a_1\)放到最后,因为中间数两两不同,所以中间也不是回文,同理后面也不会操作出回文。所以回文子数组增加\(0\)个。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;template <class Info>
struct SegmentTree {struct Node {int l, r;Info info;};std::vector<Node> tr;SegmentTree() {};SegmentTree(int n) {init(n);}SegmentTree(std::vector<Info> & info) {init(info);}void init(int n) {tr.assign(n << 2, {});build(0, n - 1);}void init(std::vector<Info> & info) {int n = info.size();tr.assign(n << 2, {});std::function<void(int, int, int)> build = [&](int l, int r, int u) -> void {tr[u] = {l, r, {}};if (l == r) {tr[u].info = info[l];return;}int mid = l + r >> 1;build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);pushup(u);};build(0, n - 1, 1);}void pushup(int u) {tr[u].info = tr[u << 1].info + tr[u << 1 | 1].info;}void build(int l, int r, int u = 1) {tr[u] = {l, r, {}};if (l == r) {tr[u].info.min = -1;tr[u].info.p = l;return;}int mid = l + r >> 1;build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);pushup(u);}void modify(int p, const Info & info, bool set = false) {int u = 1;while (tr[u].l != tr[u].r) {int mid = tr[u].l + tr[u].r >> 1;if (p <= mid) {u = u << 1;} else {u = u << 1 | 1;}}if (set) {tr[u].info = info;} else {tr[u].info = tr[u].info + info;}u >>= 1;while (u) {pushup(u);u >>= 1;}}Info query(int l, int r, int u = 1) {if (l <= tr[u].l && tr[u].r <= r) {return tr[u].info;}int mid = tr[u].l + tr[u].r >> 1;if (r <= mid) {return query(l, r, u << 1);} else if (l > mid) {return query(l, r, u << 1 | 1);}return query(l, r, u << 1) + query(l, r, u << 1 | 1);}
};struct Info {int min = -1, p;
};Info operator + (const Info & l, const Info & r) {Info res{};res = l.min < r.min || (l.min == r.min && l.p < r.p) ? l : r;return res;
}void solve() {int n, k;std::cin >> n >> k;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];-- a[i];}SegmentTree<Info> tr(n);std::vector<int> last(n, -1);for (int i = 0; i < n; ++ i) {last[a[i]] = i;}for (int i = 0; i < n; ++ i) {if (last[i] != -1) {tr.modify(i, Info{last[i], i}, true);}}for (int i = 0; i < k; ++ i) {auto [_, p] = tr.query(0, n - 1);std::cout << p + 1 << " \n"[i == k - 1];last[p] = n + i;tr.modify(p, Info{last[p], p}, true);}
}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;
}
F. Beautiful Intervals
题意:你要构造一个排列,然后有\(m\)个区间,每个区间的值为这个区间里的\(mex\)。然后使得所有区间的值的\(mex\)最小。
如果一个位置被所有区间覆盖,那么这个位置放\(0\)就行,则所有区间的\(mex > 0\),最后的\(mex = 0\)。
否则,如果有一个位置\(i\)满足没有区间的右端点是\(i\),则\(i\)可以放\(0\),\(i+1\)放\(1\)。这样覆盖\(i, i+1\)的区间\(mex > 1\),只覆盖\(i + 1\)的区间\(mex = 0\)。其它区间\(mex = 0\)。则最后\(mex = 1\)。
再否则,把\(0, n - 1\)分别放两端,中间随便放,这样的话,不是\([1, n]\)这种区间的\(mex\)要么是\(0\)要么是\(1\),\([1, n]\)这个区间\(mex = n\)。最后\(mex = 2\)。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n, m;std::cin >> n >> m; std::vector<int> d(n + 2);std::vector<int> pre(n + 1), suf(n + 1);for (int i = 0; i < m; ++ i) {int l, r;std::cin >> l >> r;++ d[l];-- d[r + 1];pre[r] = 1;suf[l] = 1;}std::vector<int> ans(n + 1);for (int i = 1; i <= n; ++ i) {d[i] += d[i - 1];if (d[i] == m) {ans[i] = 0;for (int j = 1, x = 1; j <= n; ++ j) {if (i != j) {ans[j] = x ++ ;}std::cout << ans[j] << " \n"[j == n];}return;}}for (int i = 1; i + 1 <= n; ++ i) {if (!pre[i]) {ans[i] = 0;ans[i + 1] = 1;for (int j = 1, x = 2; j <= n; ++ j) {if (j != i && j != i + 1) {ans[j] = x ++ ;}std::cout << ans[j] << " \n"[j == n];}return;} else if (!suf[i + 1]) {ans[i] = 1;ans[i + 1] = 0;for (int j = 1, x = 2; j <= n; ++ j) {if (j != i && j != i + 1) {ans[j] = x ++ ;}std::cout << ans[j] << " \n"[j == n];}return;}}ans[1] = 0;ans[n] = 1;for (int i = 2; i < n; ++ i) {ans[i] = i;}for (int i = 1; i <= n; ++ i) {std::cout << ans[i] << " \n"[i == 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;
}