A. Chores
点击查看代码
void solve() {int n, k, x;std::cin >> n >> k >> x;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}int ans = k * x;for (int i = 0; i < n - k; ++ i) {ans += a[i];}std::cout << ans << "\n";
}
B. Balanced Substring
题意:求一个\(01\)串最长的\(0\)和\(1\)个数相同的子串。
\(1\)的位置加一,\(0\)的位置减一,记录相同的前缀和。
点击查看代码
void solve() {int n;std::cin >> n;std::string s;std::cin >> s;std::vector<int> sum(n + 1);for (int i = 0; i < n; ++ i) {sum[i + 1] = sum[i] + (s[i] == '1' ? 1 : -1);}std::map<int, int> mp;int ans = 0;mp[0] = 0;for (int i = 1; i <= n; ++ i) {if (mp.count(sum[i])) {ans = std::max(ans, i - mp[sum[i]]);} else {mp[sum[i]] = i;}}std::cout << ans << "\n";
}
C. Strange Game On Matrix
题意:每一列删去最顶上的若干个一,然后从剩下的最高的一往下数最多\(k\)个,使得和最大已经修改的数最少。
模拟题,每一列搞个前缀和,然后枚举选中的第一个一。
点击查看代码
void solve() {int n, m, k;std::cin >> n >> m >> k;std::vector a(n + 1, std::vector<int>(m + 1));std::vector sum(n + 1, std::vector<int>(m + 1));for (int i = 1; i <= n; ++ i) {for (int j = 1; j <= m; ++ j) {std::cin >> a[i][j];sum[i][j] = sum[i - 1][j] + a[i][j];}}int ans = 0, cnt = 0;for (int j = 1; j <= m; ++ j) {int max = 0, del = 0;for (int i = 1; i <= n; ++ i) {if (a[i][j] == 1) {int x = std::min(n, i + k - 1);if (sum[x][j] - sum[i - 1][j] > max) {max = sum[x][j] - sum[i - 1][j];del = sum[i - 1][j];}}}ans += max;cnt += del;}std::cout << ans << " " << cnt << "\n";
}
D. Merge Sort
题意:对于归并排序,如果当前区间已经有序则返回,否则递归左右子区间。构造一个排列使得调用函数的总次数为\(k\)。
次数总为奇数,因为最开始调用了一次,然后如果要继续递归则两个子区间都会调用一次。
那么我们可以交换\(mid - 1, mid\)这两个位置,这样左右区间依然有序,并且当前区间无序,就可以向下递归。
点击查看代码
void solve() {int n, k;std::cin >> n >> k;std::vector<int> a(n);std::iota(a.begin(), a.end(), 1);auto dfs = [&](auto & self, int l, int r) -> void {if (l + 1 == r || k == 0) {return;}k -= 2;int mid = l + r >> 1;std::swap(a[mid - 1], a[mid]);self(self, l, mid);self(self, mid, r);}; k -= 1;dfs(dfs, 0, n);if (k == 0) {for (int i = 0; i < n; ++ i) {std::cout << a[i] << " \n"[i == n - 1];}} else {std::cout << -1 << "\n";}
}
E. Awards For Contestants
题意:数组从大到小排序后,把区间分成\(4\)段,第\(4\)段长度可以为\(0\)。要求前三段的长度都互相不超过另外两段的两倍,同时要求第一段最小值减第二段最大值最大,满足上面条件还要第二段最小值减第三段最大值最大,同时要求第三段最小值减第四段最大值最大。
可以枚举前两段,那么第三段可以取的区间范围也可以算出来。然后第三段的结尾我们肯定要减下一个数最大的位置,可以用线段树维护。
注意如果第四段为空,则第三段减第四段的值等于第三段的最小值。
点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)template <class Info>
struct Node {int l, r;Info info;
};template <class Info>
struct SegmentTree {std::vector<Node<Info> > tr;SegmentTree(int _n) {init(_n);}SegmentTree(std::vector<Info> & a) {init(a);}void init(int _n) {tr.assign(_n << 2, {});build(0, _n - 1);}void init(std::vector<Info> & a) {int _n = (int)a.size();tr.assign(_n << 2, {});build(0, _n - 1, a);}void pushup(int u) {tr[u].info = tr[ls].info + tr[rs].info;}void build(int l, int r, int u = 1) {tr[u] = {l, r, {}};if (l == r) {return;}int mid = l + r >> 1;build(l, mid, ls); build(mid + 1, r, rs);}void build(int l, int r, std::vector<Info> & a, int u = 1) {tr[u] = {l, r, {}};if (l == r) {tr[u].info = a[l];return;}int mid = l + r >> 1;build(l, mid, a, ls); build(mid + 1, r, a, rs);pushup(u);}void modify(int p, Info add, bool set = false) {int u = 1;while (tr[u].l != tr[u].r) {int mid = umid;if (p <= mid) {u = ls;} else {u = rs;}}if (set) {tr[u].info = add;} else {tr[u].info = tr[u].info + add;}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 = umid;if (r <= mid) {return query(l, r, ls);} else if (l > mid) {return query(l, r, rs);}return query(l, r, ls) + query(l, r, rs);}
};struct Info {int max, p;
};Info operator + (const Info & a, const Info & b) {Info res{};if (a.max >= b.max) {res = a;} else {res = b;}return res;
}void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::vector<int> id(n);std::iota(id.begin(), id.end(), 0);std::sort(id.begin(), id.end(), [&](int i, int j) {return a[i] > a[j];});SegmentTree<Info> tr(n);tr.modify(n - 1, Info{a[id[n - 1]], n - 1}, true);for (int i = n - 2; i >= 0; -- i) {tr.modify(i, Info{a[id[i]] - a[id[i + 1]], i}, true);}int p1 = 0, p2 = 1, p3 = 2;int max1 = -1, max2 = -1, max3 = -1;for (int i = 0; i + 2 < n; ++ i) {for (int j = i + 1; j + 1 < n; ++ j) {if ((i + 1) > 2 * (j - i) || j - i > 2 * (i + 1)) {continue;}int l = j + (std::max(i + 1, j - i) + 1) / 2, r = std::min(n - 1, j + std::min(i + 1, j - i) * 2);if (l > r) {continue;}auto [v3, p] = tr.query(l, r);int v1 = a[id[i]] - a[id[i + 1]], v2 = a[id[j]] - a[id[j + 1]];if (v1 > max1 || (v1 == max1 && v2 > max2) || (v1 == max1 && v2 == max2 && v3 > max3)) {max1 = v1;max2 = v2;max3 = v3;p1 = i;p2 = j;p3 = p;}}}std::vector<int> ans(n, -1);for (int i = 0; i <= p1; ++ i) {ans[id[i]] = 1;}for (int i = p1 + 1; i <= p2; ++ i) {ans[id[i]] = 2;}for (int i = p2 + 1; i <= p3; ++ i) {ans[id[i]] = 3;}for (int i = 0; i < n; ++ i) {std::cout << ans[i] << " \n"[i == n - 1];}
}