Codeforces Round #744 (Div. 3)
A. Casimir's String Solitaire
meaning of the title
Give A string consisting only of characters' A ',' B 'and' C '. You can eliminate one' A 'and one' B 'at A time, or one' B 'and one' C 'at the same time. Ask whether all characters can be eliminated in the end.
thinking
It can be completely eliminated as long as the number of 'B' is equal to the sum of the numbers of 'A' and 'C'.
Time complexity
O ( 1 ) O(1) O(1)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
A - Casimir's String Solitaire | GNU C++17 | Accepted | 15 ms | 3600 KB |
#include <bits/stdc++.h> using namespace std; char s[55]; void solve() { scanf("%s", s); int n = strlen(s); //Finding the number of characters in advance can reduce the complexity, but putting strlen into the loop can also pass this problem int a = 0, b = 0; //A the sum of the number of records' a 'and' C ', B the number of records' B' for (int i = 0; i < n; ++i) { if (s[i] == 'B') ++b; else ++a; } if (a == b) printf("YES\n"); else printf("NO\n"); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
B. Shifting Sort
meaning of the title
Give a sequence of integers, one interval at a time [ l , r ] [l,r] [l,r], select a positive integer d d d. Parallel interval [ l , r ] [l,r] [l,r] cycle shift left d d d positions, at most n n After n operations, the sequence is ordered from small to large, and each operation needs to be output.
thinking
We can use the selective sorting method, select the minimum value, move it to the first position left, then select the minimum value in the remaining number, move it to the second position left, and so on. Note that if the minimum value is already in the first place, no operation is required.
Time complexity
O ( n 2 ) O(n^2) O(n2)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
B - Shifting Sort | GNU C++17 | Accepted | 31 ms | 3600 KB |
#include <bits/stdc++.h> using namespace std; struct dt { int l, r, d; dt(int ll, int rr, int dd) { //Constructor for empty_ back l = ll, r = rr, d = dd; //Instead of writing the constructor, replace it with push_back can also do it } }; int a[55], b[55]; void solve() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); vector<dt> v; //Record operation for (int i = 1; i <= n; ++i) { int mn = i; //Record the location of the minimum value for (int j = i + 1; j <= n; ++j) if (a[j] < a[mn]) mn = j; if (mn == i) continue; //The minimum value is exactly the first int d = mn - i; v.emplace_back(i, n, d); //Record operation for (int j = i; j <= n; ++j) { //Simulate circular movement and update the array if (j - d >= i) b[j - d] = a[j]; else b[n + 1 + j - d - i] = a[j]; } for (int j = i; j <= n; ++j) a[j] = b[j]; } printf("%d\n", v.size()); for (auto &i: v) printf("%d %d %d\n", i.l, i.r, i.d); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
C. Ticks
meaning of the title
Give a n n n line m m The grid array of m columns defines the pattern "check": ∀ h ∈ [ 0 , d ] \forall h\in[0,d] ∀ h ∈ [0,d], coordinates ( i − h , j ± h ) (i-h,j\pm h) The squares of (i − h,j ± h) are blackened ( i , j ) (i,j) (i,j) is the center and the height is d d d "check". Ask whether a given grid array can be composed of several heights not less than k k k's "cross check" composition (different cross checks are allowed to overlap).
thinking
The center of existence is located in ( i , j ) (i,j) (i,j), height d d The necessary and sufficient conditions for "checking" of d are: ( i , j ) (i,j) (i,j) start, with at least d d d consecutive black squares. Similarly, the necessary and sufficient condition for a black grid to belong to a "check mark" is: from this position ( x , y ) (x,y) (x,y) start looking in the lower left and lower right directions, and you can find a position ( i , j ) (i,j) (i,j) so that there is a center located at ( i , j ) (i,j) (i,j), not less than x − i x-i "Check" of x − i. Therefore, it is only necessary to preprocess the longest number of continuous black grids in the upper left and right directions at each position, and then judge whether the conditions are met.
Time complexity
O ( n 3 ) O(n^3) O(n3)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
C - Ticks | GNU C++17 | Accepted | 31 ms | 3700 KB |
#include <bits/stdc++.h> using namespace std; char s[20][20]; int a[20][20], b[20][20]; //Array a records the number of the longest continuous black squares at the top left, and array b records the number of black squares at the top right int n, m, k; bool check() { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (s[i][j] == '.') continue; //Only the black squares are judged, and the white squares are directly ignored bool ok = false; int x, y, cnt; x = i, y = j, cnt = 0; while (x < n && y < m) { if (a[x][y] >= max(k, cnt) && b[x][y] >= max(k, cnt)) { //Upper left and upper right shall be met at the same time ok = true; break; } ++cnt, ++x, ++y; } if (ok) continue; x = i, y = j, cnt = 0; while (x < n && y >= 0) { if (a[x][y] >= max(k, cnt) && b[x][y] >= max(k, cnt)) { ok = true; break; } ++cnt, ++x, --y; } if (!ok) return false; } } return true; } void solve() { scanf("%d%d%d", &n, &m, &k); for (int i = 0; i < n; ++i) scanf("%s", s[i]); memset(a, 0, sizeof a); memset(b, 0, sizeof b); for (int i = 0; i < n - 1; ++i) //The number of continuous black lattices in the upper left direction is calculated by recursion in the lower right direction for (int j = 0; j < m - 1; ++j) if (s[i][j] == '*' && s[i + 1][j + 1] == '*') a[i + 1][j + 1] = a[i][j] + 1; for (int i = 0; i < n - 1; ++i) //Recursion to the lower left to find the number of continuous black lattices in the upper right direction for (int j = m - 1; j > 0; --j) if (s[i][j] == '*' && s[i + 1][j - 1] == '*') b[i + 1][j - 1] = b[i][j] + 1; if (check()) printf("YES\n"); else printf("NO\n"); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { solve(); } return 0; }
D. Productive Meeting
meaning of the title
At the meeting n n n individuals, No i i i people are willing to discuss at most a i a_i ai # times, any two people can discuss any number of times. The topic requires to find out the maximum number of discussions and output the discussion scheme.
thinking
Greedily find out the two people who are willing to discuss the most times, make them discuss once, and repeat this operation until no more two people are willing to discuss. In order to find the most frequent people, just use the heap (priority queue).
Time complexity
O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Productive Meeting | GNU C++17 | Accepted | 109 ms | 7300 KB |
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; void solve() { int n; scanf("%d", &n); priority_queue<pii> q; //Large top reactor for (int i = 1; i <= n; ++i) { int p; scanf("%d", &p); if (p) q.emplace(p, i); } vector<pii> v; //Used to record the process while (q.size() > 1) { pii a = q.top(); //Two elements at the top of the heap were found q.pop(); pii b = q.top(); q.pop(); v.emplace_back(a.second, b.second); //Record a discussion --a.first, --b.first; //Reduce the number of discussions if (a.first) q.push(a); if (b.first) q.push(b); } printf("%d\n", v.size()); for (auto &i: v) printf("%d %d\n", i.first, i.second); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
E1. Permutation Minimization by Deque
meaning of the title
Give a sequence and join an empty double ended queue in turn. You can optionally join from the beginning or the end. Find the result of the smallest possible dictionary order. Please understand the meaning of dictionary order by yourself.
thinking
Adopt the greedy strategy. If the newly added element is greater than the team head, it will be added at the end of the team, otherwise it will be added at the head of the team. Simulation results can be obtained.
Time complexity
O ( n ) O(n) O(n)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
E1 - Permutation Minimization by Deque | GNU C++17 | Accepted | 109 ms | 4700 KB |
#include <bits/stdc++.h> using namespace std; void solve() { int n; scanf("%d", &n); deque<int> q; //Double ended queue int p; scanf("%d", &p); q.push_back(p); //Add the first element directly for (int i = 1; i < n; ++i) { scanf("%d", &p); //Add the remaining elements after comparison if (p > q.front()) q.push_back(p); else q.push_front(p); } for (int i: q) printf("%d ", i); //output printf("\n"); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
E2. Array Optimization by Deque
meaning of the title
Give a sequence and join an empty double ended queue in turn. You can optionally join from the beginning or the end. Find the least possible reverse order pairs. Please understand the meaning of reverse order pairs.
thinking
Consider the last element. Whether it is at the head of the team or at the end of the team, the number of reverse pairs generated is independent of the order of other elements. Therefore, greedily select the scheme with less reverse pairs. Then, the penultimate element is processed in exactly the same way as the last element. Note: when processing the penultimate element, it is not necessary to consider whether it will have an inverse pair with the last element, because it has been calculated during the calculation of the last element. Repeat this operation to process all elements. To calculate the number of pairs in reverse order, you can use a tree array. The data range of this problem is large and needs to be discretized first.
Time complexity
O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
E2 - Array Optimization by Deque | GNU C++17 | Accepted | 280 ms | 11700 KB |
#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int a[N], d[N], cnt; //cnt records the quantity after discretization int lowbit(int x) { return x & -x; } void upd(int x, int k) { //Single point modification of tree array for (int i = x; i <= cnt; i += lowbit(i)) d[i] += k; } int sum(int x) { //Tree array interval summation int r = 0; for (int i = x; i > 0; i -= lowbit(i)) r += d[i]; return r; } void solve() { int n; scanf("%d", &n); map<int, int> m; //For discretization for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); m[a[i]]; } cnt = 0; for (auto &i: m) i.second = ++cnt; for (int i = 1; i <= n; ++i) a[i] = m[a[i]], upd(a[i], 1); //Discretize and add 1 to this position in the tree array long long ans = 0; for (int i = n; i >= 1; --i) { int l = sum(a[i] - 1), r = sum(cnt) - sum(a[i]); if (l > r) ans += r, upd(a[i], -1); else ans += l, upd(a[i], -1); } printf("%lld\n", ans); memset(d, 0, (cnt + 5) << 2); //Remember to empty the tree array } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
F. Array Stabilization (AND version)
meaning of the title
There is an array of 0 and 1 only a a a. Memory array a a a cycle shift left d d The sequence obtained after d positions is a → d a^{\to d} a → d, right now a a Each element of a a i a_i ai, replace with a i & a i → d a_i\&a_i^{\to d} ai & ai → d, called one operation. The operation is repeated until the whole sequence does not change, which is called steady state. It is required to judge whether 1 still exists in the stable state. If so, output - 1. Otherwise, calculate the operands required from the initial state to the stable state.
thinking
if and only if a i = a ( i − d + n ) % n = 1 a_i=a_{(i-d+n)\%n}=1 When ai = a(i − d+n)%n = 1, after one operation, a i a_i ai is still 1. So we just need violence to simulate jumping d d For the operation of d positions, find the longest continuous number of 1, and then you can get the answer. In this process, there is a property: order k = g c d ( n , d ) k=gcd(n,d) k=gcd(n,d) (gcd represents the greatest common divisor), then we can find k k k independent cycles, and the length of each cycle is n k \frac{n}{k} kn. So when the number of consecutive ones reaches n k \frac{n}{k} When kn , it indicates that 1 will exist no matter how many operations.
Friendly reminder 1: attention d d d data range, d = n d=n d=n is possible, which will lead to some writing timeout, which can pass the special judgment d = n d=n d=n solution.
Friendly reminder 2: the above-mentioned "properties" can be rigorously expressed and proved by the methods of groups and subgroups in discrete mathematics, and will not be explained here.
Friendly reminder 3: the data range of this question is very large. The solution seems violent, but in fact it is not complex. You can write it at ease.
Time complexity
O ( n ) O(n) O(n)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
F - Array Stabilization (AND version) | GNU C++17 | Accepted | 249 ms | 11500 KB |
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int a[N], b[N]; void solve() { int n, d; scanf("%d%d", &n, &d); memset(b, 0, (n + 5) << 2); //Don't use all memset s. It's easy to time out for (int i = 0; i < n; ++i) scanf("%d", &a[i]); if (d == n) { //Special judgment d=n for (int i = 0; i < n; ++i) { if (a[i]) { printf("-1\n"); return; } } printf("0\n"); return; } int k = __gcd(n, d), lim = n / k, ans = 0; for (int i = 0; i < k; ++i) { int pos = i; for (int j = 0; j < 2 * lim; ++j) { //Two rounds of simulation shall be carried out to avoid errors due to the connection between the head and the tail if (a[(pos + d) % n]) b[(pos + d) % n] = b[pos % n] + 1; if (b[(pos + d) % n] >= lim) { //There must be a case of 1 printf("-1\n"); return; } pos = (pos + d) % n; } } for (int i = 0; i < n; ++i) ans = max(ans, b[i]); printf("%d\n", ans); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }
G. Minimal Coverage
meaning of the title
There are several line segments on a one-dimensional number axis, and the starting point of the first line segment is at 0. Given the length of the line segment, the adjacent line segments must be connected from end to end, but the direction must not be the same. Find the minimum total coverage length after these line segments are connected.
The meaning of the question is difficult to understand. For example, the length of the line segment is [ 7 , 8 , 6 ] [7,8,6] [7,8,6], the first line segment covers the interval [ 0 , 7 ] [0,7] [0,7], the second line segment covers the interval [ − 1 , 7 ] [-1,7] [− 1,7], the third line segment covers the interval [ − 1 , 5 ] [-1,5] [− 1,5], then the total coverage is [ − 1 , 7 ] [-1,7] [− 1,7], length 8.
thinking
The general idea adopts the dichotomy strategy to dichotomy the answer, and the upper bound of dichotomy is 2 ⋅ m a x a i 2\cdot max\ a_i 2⋅max ai. Value for each attempt m i d mid mid, we can record the possible position of the tail end of the processed line segment, and update the possible position every time a new line segment is added. Because this position cannot be more than m i d mid mid units, we need to delete out of range locations (we can update without adding).
Method optimization 1: using bitset in STL container to optimize the operation of updating possible locations can greatly improve efficiency and reduce the amount of code (using left shift, right shift, and, or operation).
Method optimization 2: there may be negative numbers at the end of the line segment, so it will be troublesome to directly use the array or bitset (you need to add an appropriate number to convert the negative number into a positive number). In fact, it doesn't matter where the starting point of the first line segment is (that is, it doesn't have to start from 0), so you might as well set the initial state to 0 m i d mid mid 1. This method requires a certain understanding ability, and can not be used if it cannot be understood. The code provided below adopts this method.
Time complexity
O ( n l o g 2 n ⋅ m a x a i ) O(nlog_2n\cdot max\ a_i) O(nlog2n⋅max ai)
AC code
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
G - Minimal Coverage | GNU C++17 | Accepted | 46 ms | 3700 KB |
#include <bits/stdc++.h> using namespace std; int a[10005]; int n; bool check(int x) { bitset<2005> b, c; for (int i = 0; i <= x; ++i) b[i] = c[i] = true; //Moving left means the direction of the line segment is negative, and moving right means positive for (int i = 0; i < n; ++i) b = (b << a[i] | b >> a[i]) & c; //&The purpose of C is to remove out of range positions return b.any(); } void solve() { scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%d", &a[i]); int l = 0, r = 2000, ans; //Two point answer while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } printf("%d\n", ans); } int main() { // freopen("in.txt", "r", stdin); int t; scanf("%d", &t); while (t--) solve(); return 0; }