Deltix Round, Autumn 2021 (open for everyone, rated, Div. 1 + Div. 2)
A. Divide and Multiply
It can be found that it is optimal to multiply only one number at a time. Because the range is very small, you can enumerate which number to multiply by \ (2 \), and note that the answer is that the exponential level should be on \ (long~long \).
#include<bits/stdc++.h> using namespace std; #define int long long const int MAXN = 15 + 5; int a[MAXN], b[MAXN]; int32_t main(int argc, char *argv[]) { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int T; cin >> T; while (T--) { int n; cin >> n; for (int i = 1; i <= n; ++i) { cin >> a[i]; } int res = 0; for (int i = 1; i <= n; ++i) { memcpy(b, a, sizeof(a)); for (int j = 1; j <= n; ++j) { if (i == j) continue; while (b[j] % 2 == 0) { b[j] >>= 1; b[i] <<= 1; } } int sum = 0; for (int j = 1; j <= n; ++j) { sum += b[j]; } res = max(res, sum); } cout << res << '\n'; } // system("pause"); return 0; }
B. William the Vigilant
It can be found that the answer is the number of \ (abc \), so for each modification, we can calculate the substring including this position.
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; char s[MAXN]; int main(int argc, char *argv[]) { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int n, m; cin >> n >> m >> s + 1; // Judge whether the substring of [x, x + 2] is abc auto check = [&](int x) -> bool { return 1 <= x && x + 2 <= n && s[x] == 'a' && s[x + 1] == 'b' && s[x + 2] == 'c'; }; int cnt = 0; for (int i = 1; i <= n; ++i) { if (check(i)) { ++cnt; } } while (m--) { int p; char c; cin >> p >> c; for (int i = p - 2; i <= p; ++i) { cnt -= check(i); } s[p] = c; for (int i = p - 2; i <= p; ++i) { cnt += check(i); } cout << cnt << '\n'; } // system("pause"); return 0; }
C. Complex Market Analysis
To multiply subarrays into prime numbers, there is at most one prime number, and the other numbers are \ (1 \). Then, for each prime number, we just need to find the most continuous \ (1 \) to the left and right, and multiply it according to the multiplication principle.
#include<bits/stdc++.h> using namespace std; #define int long long const int MAXN = 1e6 + 5; bool isNotP[MAXN]; int p[MAXN], cnt; void seive() { isNotP[1] = true; for (int i = 2; i < MAXN; ++i) { if (!isNotP[i]) { p[++cnt] = i; } for (int j = 1; j <= cnt && i * p[j] < MAXN; ++j) { isNotP[i * p[j]] = true; if (i % p[j] == 0) { break; } } } } int a[MAXN]; int32_t main(int argc, char *argv[]) { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); seive(); int T; cin >> T; while (T--) { int n, k; cin >> n >> k; for (int i = 1; i <= n; ++i) { cin >> a[i]; } int res = 0; for (int i = 1; i <= n; ++i) { if (isNotP[a[i]]) continue; int l = 0; for (int j = i + k; j <= n; j += k) { if (a[j] != 1) { break; } ++l; } int r = 0; for (int j = i - k; j >= 1; j -= k) { if (a[j] != 1) { break; } ++r; } // The current position contribution is: the subsequence containing only the left 1 + the subsequence containing only the right 1 + the subsequence containing the left and right 1 res += l + r + l * r; } cout << res << '\n'; } // system("pause"); return 0; }
D. Social Network
The description of this problem is a little complicated. In fact, it is a parallel search set simulation problem.
Firstly, we give the restrictions of \ (m \) pairs. For each \ (i ~ \epsilon ~ [1, m] \), we can let any \ (i \) pair of people know each other, that is, the merging of the join query set, but finally your join query set must meet the first \ (i \) restrictions, requiring the size of the largest pass block of the possible join query set.
For the second example given in the topic, when we need to meet the first four constraints, we first combine \ ([1,2], [2,3], [3,4] \), and at this time we can also specify \ (1 \) relationships, so the largest connected block must be assigned first, because other connected blocks are \ (1 \), and we can specify a pair of relationships \ ([4,5]) \), so \ (1 \) knows \ (4 \) at most Personal.
Then we can discuss it in two cases. Suppose we want to judge the relationship \ (x_i,y_i \):
\(\ bullet \) if \ (x_i \) and \ (y_i \) are already in the same block, we can specify a pair of relationships at will. In order to maximize the answer, we should give priority to the large connected block.
\(\ bullet \) otherwise, we can only let them merge first to meet the subject constraints.
In order to meet the first \ (I \) constraints, we must first meet the first \ (i-1 \) constraints, so we can enumerate the number of conditions. If we do not meet the current constraints, that is, we are not in the same block, we first merge them, otherwise we use a counter \ (scc \) to record the number of times we can specify at will. For each query, we violently traverse the set, find the sizes of all connected blocks, and sort the top \ (scc \) from large to small.
#include<bits/stdc++.h> using namespace std; #define int long long const int MAXN = 1e3 + 5; int fa[MAXN], sz[MAXN]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } bool merge(int x, int y) { x = find(x), y = find(y); if (x == y) { return false; } fa[x] = y; sz[y] += sz[x]; return true; } int X[MAXN], Y[MAXN]; int32_t main(int argc, char *argv[]) { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int n, m; cin >> n >> m; for (int i = 1; i <= n; ++i) { fa[i] = i; sz[i] = 1; } for (int i = 1; i <= m; ++i) { cin >> X[i] >> Y[i]; } // scc records can be specified several times at will int scc = 0; for (int i = 1; i <= m; ++i) { int x = X[i], y = Y[i]; // Merge failed, i.e. counter + 1 when two people know each other if (!merge(x, y)) { ++scc; } vector<int> a; for (int j = 1; j <= n; ++j) { if (j == find(j)) { a.push_back(sz[j]); } } sort(a.begin(), a.end(), greater<int>()); int res = 0; for (int j = 0; j < min((int)a.size(), scc + 1); ++j) { res += a[j]; } cout << res - 1 << '\n'; } // system("pause"); return 0; }
E. William The Oblivious
Different from the \ (b \) question, this question needs to satisfy that the subsequence is not \ (abc \) rather than substring.
Consider the segment tree to solve this problem. The most complex part of this problem is the push-up part. We use \ (abc \) to represent the minimum number of modifications without \ (abc \), \ (ab,bc \) and so on.
First, we solve the problem that only the string of \ (ab \) needs to satisfy the condition that there is no \ (ab \), assuming that the current node is \ (p \). If we already know the \ (ab \) of the right son, that is, there will only be \ (ba \) on the right, we only need to change all \ (a \) of the left son into \ (b \). If we already know the left son \ (ab \), we only need to change all \ (b \) of the right son into \ (a \), That is \ (tree[p].ab = min(tree[ls(p)].a + tree[rs(p)].ab, tree[ls(p)].ab + tree[rs(p)].b) \).
\(ac,bc \) can be calculated similarly. Finally, we need to calculate \ (abc \). Similarly, if we know the \ (abc \) of the right son, there may be \ (acb,bac,bca,cba,cab \) on the right, because there may be subsequences such as \ (bc \), we need to modify all \ (a \) of the left son. The same is true for other situations.
Because it is a single point of modification, you can push it up after each modification.
#include<bits/stdc++.h> using namespace std; #define int long long const int MAXN = 1e5 + 5; char s[MAXN]; #define ls(x) x << 1 #define rs(x) x << 1 | 1 struct Node { int l, r; int a, b, c, ab, ac, bc, abc; int mid() { return (l + r) >> 1; } } tree[MAXN << 2]; void pushup(int p) { tree[p].a = tree[ls(p)].a + tree[rs(p)].a; tree[p].b = tree[ls(p)].b + tree[rs(p)].b; tree[p].c = tree[ls(p)].c + tree[rs(p)].c; tree[p].ab = min(tree[ls(p)].a + tree[rs(p)].ab, tree[ls(p)].ab + tree[rs(p)].b); tree[p].bc = min(tree[ls(p)].b + tree[rs(p)].bc, tree[ls(p)].bc + tree[rs(p)].c); tree[p].abc = min({ tree[ls(p)].a + tree[rs(p)].abc, tree[ls(p)].ab + tree[rs(p)].bc, tree[ls(p)].abc + tree[rs(p)].c }); } void build(int l, int r, int p) { tree[p].l = l, tree[p].r = r; if (l == r) { tree[p].a = (s[l] == 'a'); tree[p].b = (s[l] == 'b'); tree[p].c = (s[l] == 'c'); return ; } int mid = (l + r) >> 1; build(l, mid, ls(p)); build(mid + 1, r, rs(p)); pushup(p); } void modify(int l, int r, char c, int p) { if (l <= tree[p].l && tree[p].r <= r) { s[l] = c; tree[p].a = (s[l] == 'a'); tree[p].b = (s[l] == 'b'); tree[p].c = (s[l] == 'c'); return ; } int mid = tree[p].mid(); if (l <= mid) modify(l, r, c, ls(p)); if (r > mid) modify(l, r, c, rs(p)); pushup(p); } int32_t main(int argc, char *argv[]) { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int n, m; cin >> n >> m >> s + 1; build(1, n, 1); while (m--) { int p; char c; cin >> p >> c; modify(p, p, c, 1); cout << tree[1].abc << '\n'; } // system("pause"); return 0; }