A. Casimir's String Solitaire
-
meaning of the title
Give you a string. You can delete AB or BC. Ask if you can delete the string and make it empty. -
Problem solving ideas
Check in, judge c n t a + c n t c = c n t b cnt_a+cnt_c=cnt_b cnta+cntc=cntb. -
AC code
/** *@filename:A_Casimir_s_String_Solitaire *@author: pursuit *@created: 2021-09-28 22:35 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 1e5 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t; string s; void solve(){ } int main(){ cin >> t; while(t -- ){ cin >> s; int cnt[3]; cnt[0] = cnt[1] = cnt[2] = 0; for(int i = 0; i < s.size(); ++ i){ cnt[s[i] - 'A'] ++; } if(cnt[1] == cnt[0] + cnt[2])puts("YES"); else puts("NO"); } solve(); return 0; }
B. Shifting Sort
-
meaning of the title
Given an array, you can select an interval at a time [ l , r ] [l,r] [l,r] then cycle left d d d. You need to turn the array into an incremental operation output. The total number of operations cannot exceed n n n. -
Problem solving ideas
It is not difficult to find that we can put a maximum value on the far right every time, that is, we first find the second value we want to determine i i The number of i, then it must be before i i Of the number i, we just need to find the position of this number l l l. Then take the position where it should appear r r r. Operate [ l , r ] [l,r] [l,r] cycle shift left 1 1 1 digit is enough. Then the simulation is carried out in turn. -
AC code
/** *@filename:B_Shifting_Sort *@author: pursuit *@created: 2021-09-28 22:39 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 50 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, a[N], b[N]; struct node{ int l, r, d; }; void solve(){ //The maximum value can be determined each time. Move the maximum value to the corresponding position. vector<node> res; int k = n; sort(b + 1, b + 1 + n); while(k){ int idx = 0; for(int i = 1; i <= k; ++ i){ if(a[i] == b[k]){ idx = i; break; } } //i should go to k. if(idx == k){ -- k; continue; } else res.push_back({idx, k, 1}); //Modify ai. for(int i = idx; i < k; ++ i)a[i] = a[i + 1]; a[k] = b[k]; -- k; } cout << res.size() << endl; for(int i = 0; i < res.size(); ++ i){ cout << res[i].l << " " << res[i].r << " " << res[i].d << endl; } } int main(){ cin >> t; while(t -- ){ cin >> n; for(int i = 1; i <= n; ++ i){ cin >> a[i]; b[i] = a[i]; } solve(); } return 0; }
C. Ticks
-
meaning of the title
Give you a map and ask if you can draw it to form this map. The draw operation selects a point for ( i , j ) (i,j) (i,j), draw it in black, and draw the left diagonal and right diagonal at the same time x x x squares are painted in black, which needs to be met x ≥ d x\geq d x≥d. -
Problem solving ideas
From the question, we can simulate, that is, select a starting point from bottom to top ( i , j ) (i,j) (i,j), and then make reasonable adjustments d f s dfs dfs judges whether it is feasible. If it is feasible, draw it and mark it with vis array. Finally, check whether all the black grids have been marked. -
AC code
/** *@filename:C_Ticks *@author: pursuit *@created: 2021-09-28 23:22 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 20 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, m, k; char s[N][N]; bool vis[N][N];//Whether the mark can be stained. int dfs1(int x, int y, bool flag, int res){ int ans = 1; if(flag && res == 0)return ans; if(x - 1 >= 1 && x - 1 <= n && y - 1 >= 1 && y - 1 <= m && s[x - 1][y - 1] == '*'){ ans += dfs1(x - 1, y - 1, flag, res - 1); } if(flag)vis[x][y] = true; return ans; } int dfs2(int x, int y, bool flag, int res){ int ans = 1; if(flag && res == 0)return ans; if(x - 1 >= 1 && x - 1 <= n && y + 1 >= 1 && y + 1 <= m && s[x - 1][y + 1] == '*'){ ans += dfs2(x - 1, y + 1, flag, res - 1); } if(flag)vis[x][y] = true; return ans; } void solve(){ bool flag = false; for(int i = n; i >= 1; -- i){ for(int j = m; j >= 1; -- j){ if(s[i][j] == '*'){ int x = dfs1(i, j, false, 0) - 1, y = dfs2(i, j, false, 0) - 1; //cout << i << " " << j << " " << x << " " << y << endl; if(min(x, y) < k && !vis[i][j]){ flag = true; break; } else if(min(x, y) >= k){ dfs1(i, j, true, min(x, y) + 1), dfs2(i, j, true, min(x, y) + 1); } } } if(flag)break; } for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= m; ++ j){ if(s[i][j] == '*' && !vis[i][j])flag = true; } } if(flag)puts("NO"); else puts("YES"); } int main(){ cin >> t; while(t -- ){ cin >> n >> m >> k; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; ++ i)cin >> s[i] + 1; solve(); } return 0; }
D. Productive Meeting
-
meaning of the title
Given an array a a a. Each time you need to select two array elements, they are greater than 0 0 0 a [ i ] a[i] a[i] and a [ j ] a[j] a[j], and then subtract them all 1 1 1. Ask the maximum number of operations. -
Problem solving ideas
Priority queue or multiset can be used. Here, I use muliset to take out the real-time maximum and minimum values for operation every time, and update them after operation.
ps: it seems that there is a conclusion that it is also optimal to take out the real-time maximum value and sub maximum value for operation every time. Priority queue can be used here. Please implement it yourself. -
AC code
/** *@filename:D_Productive_Meeting *@author: pursuit *@created: 2021-09-28 22:55 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 2e5 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, a[N]; struct node{ int i; bool operator < (const node &A) const{ return a[i] < a[A.i]; } }; void solve(){ multiset<node> s; vector<pii> res; for(int i = 1; i <= n; ++ i)s.insert({i}); while(s.size() > 1){ auto iter1 = s.begin(), iter2 = s.end(); -- iter2; int x = (*iter1).i, y = (*iter2).i; if(a[x] == 0){ s.erase(iter1); continue; } if(a[y] == 0){ s.erase(iter2); continue; } -- a[x], -- a[y]; s.erase(iter1), s.erase(iter2); s.insert({x}), s.insert({y}); res.push_back({x, y}); } cout << res.size() << endl; for(auto iter : res){ cout << iter.first << " " << iter.second << endl; } } int main(){ scanf("%d", &t); while(t -- ){ scanf("%d", &n); for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); } solve(); } return 0; }
E1. Permutation Minimization by Deque
-
meaning of the title
You need to put the array in order p p When p is put into the double ended queue, you need to minimize the dictionary order of the double ended queue. -
Problem solving ideas
It is not difficult to find that the queue head of double ended queue is the existence that really determines the size of dictionary order, so we need to minimize the queue head. This simulates the operation. -
AC code
/** *@filename:E1_Permutation_Minimization_by_Deque *@author: pursuit *@created: 2021-09-28 22:49 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 2e5 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, p[N]; void solve(){ deque<int> q; q.push_back(p[1]); for(int i = 2; i <= n; ++ i){ int x = q.front(); if(p[i] < x)q.push_front(p[i]); else q.push_back(p[i]); } while(!q.empty()){ cout << q.front() << " "; q.pop_front(); } cout << endl; } int main(){ scanf("%d", &t); while(t -- ){ scanf("%d", &n); for(int i = 1; i <= n; ++ i){ scanf("%d", &p[i]); } solve(); } return 0; }
E2. Array Optimization by Deque
-
meaning of the title
You need to put the array in order p p When p is put into the double ended queue, you need to minimize the number of reverse pairs after putting. -
Problem solving ideas
Since both the front and back faces are compared with the existing number in the queue, the order in the queue will not be considered in this calculation. Therefore, the number to be placed after we put the front and back faces has no impact, that is, we only need to consider which is the smaller of the cost of putting the front face and the cost of putting the back face. In fact, if you put it in the front, all less than it should be counted, and if you put it in the back, all greater than it should be counted. This is realized by tree array. Pay attention to discretization. -
AC code
/** *@filename:E2_Array_Optimization_by_Deque *@author: pursuit *@created: 2021-09-28 23:41 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 2e5 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, a[N]; int c[N]; vector<int> temp; int lowbit(int x){ return x & (- x); } void add(int x, int v){ while(x <= n){ c[x] += v; x += lowbit(x); } } ll get(int x){ ll ans = 0; while(x){ ans += c[x]; x -= lowbit(x); } return ans; } void solve(){ //Discretization. You can remember this discretization operation. sort(temp.begin(), temp.end()); temp.erase(unique(temp.begin(), temp.end()), temp.end()); for(int i = 1; i <= n; ++ i){ a[i] = lower_bound(temp.begin(), temp.end(), a[i]) - temp.begin() + 1; } ll res = 0; for(int i = 1; i <= n; ++ i){ res += min(get(a[i] - 1), get(n) - get(a[i])); add(a[i], 1); } printf("%lld\n", res); } int main(){ scanf("%d", &t); while(t -- ){ scanf("%d", &n); temp.resize(n); for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); temp[i - 1] = a[i]; c[i] = 0; } solve(); } return 0; }
F. Array Stabilization (AND version)
-
meaning of the title
Given an array n, the subscript starts from 0 and contains only 0 and 1. Given d. Now you need to determine how many times the array elements are all 0.
The operation is to rotate the array d d d. Then combine with the original array to get a new array. -
Problem solving ideas
Due to the characteristics of and operation, it is 0 0 The location of 0 will only be 0 0 0, and it can change other positions into 1 1 1. This can be understood as movement, which can obviously be realized through b f s bfs bfs, but in order to avoid excessive complexity, we need to reduce repeated steps (i.e. points that have been placed in the priority queue). At this point, the simulation operation is OK. -
AC code
/** *@filename:F_Array_Stabilization_AND_version_ *@author: pursuit *@created: 2021-09-29 17:17 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 1e6 + 10; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; // int t, n, d, a[N]; pii q[N]; int st, ed; void solve(){ st = 1, ed = 0; int res = 0; for(int i = 0; i < n; ++ i){ if(!a[i])q[++ ed] = {0, i}; } while(st <= ed){ auto x = q[st ++]; int u = (x.second + d) % n; if(a[u]){ a[u] = 0; q[++ ed] = {x.first + 1, u}; res = max(res, x.first + 1); } } for(int i = 0; i < n; ++ i){ if(a[i]){ res = -1; break; } } printf("%d\n", res); } int main(){ scanf("%d", &t); while(t -- ){ scanf("%d%d", &n, &d); for(int i = 0; i < n; ++ i){ scanf("%d", &a[i]); } solve(); } return 0; }
G. Minimal Coverage
-
meaning of the title
N line segments are given in sequence. Starting from 0, each line segment can be placed forward or backward (+ x,-x), but the starting end must be placed at the end of the previous line segment. Ask the minimum coverage interval length after n bars are placed. -
Problem solving ideas
When we first see this problem, we will find that the information to be saved is too much and very complex, but in fact, we can make some constraints, that is, we can fix the left endpoint in 0 0 0, i.e. the left endpoint is not at 0 0 We can implement the offset at 0, which does not affect the answer.
Otherwise, it is found that the local solution can constitute the optimal solution, because we have to use the last result every time.
So we use d p [ i ] [ j ] dp[i][j] dp[i][j] indicates the front i i i line segments, and the end position is j j j is the length of the line segment.
The initial state is dp[1][a[1]] and the termination state is dp[n][j].
Note that we need to always ensure that the left endpoint is 0, which is convenient for us to handle. If it is not 0, we can offset it, so the array length needs to be opened to 2000
state transition
If it is placed in the right direction, we don't need to consider out of bounds (that is, there will be no negative array subscript), so we just need to enumerate d p [ i − 1 ] [ j ] dp[i - 1][j] dp[i−1][j],
Then dp[i][j + a[i]] = min(dp[i][j + a[i]], max(dp[i - 1][j], j + a[i]); Note that the segment length is updated,
If it is reversed, it is necessary to consider the out of bounds, that is, the size relationship between j and a[i].
If j ≤ a [ i ] j \leq a[i] j ≤ a[i], then the reverse amplification will exceed 0. At this time, we can offset it, that is, the interval coverage length is relatively increased by a[i] - j.
Then dp[i][0] = min(dp[i][0], dp[i - 1][j] + a[i] - j).
Otherwise, it will not exceed the left boundary, dp[i][j - a[i]] = min(dp[i][j - a[i]], dp[i - 1][j]);
So far, the problem is solved. -
AC code
/** *@filename:G_Minimal_Coverage *@author: pursuit *@created: 2021-09-29 20:05 **/ #include <bits/stdc++.h> #define debug(a) cout << "debug : " << (#a)<< " = " << a << endl using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N = 1e4 + 10, M = 2010; const int P = 1e9 + 7; const int INF = 0x3f3f3f3f; int t, n, a[N]; int dp[N][M];//dp[i][j] represents the length of the first I line segments and the end position is j. void solve(){ dp[1][a[1]] = a[1]; for(int i = 2; i <= n; ++ i){ for(int j = 0; j < M; ++ j){ if(j <= a[i]){ dp[i][0] = min(dp[i][0], dp[i - 1][j] + a[i] - j); } else{ dp[i][j - a[i]] = min(dp[i][j - a[i]], dp[i - 1][j]); } dp[i][j + a[i]] = min(dp[i][j + a[i]], max(dp[i - 1][j], j + a[i])); } } int res = INF; for(int j = 0; j < M; ++ j){ res = min(res, dp[n][j]); } printf("%d\n", res); } int main(){ scanf("%d", &t); while(t -- ){ scanf("%d", &n); for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); for(int j = 0; j < M; ++ j){ dp[i][j] = INF; } } solve(); } return 0; }