本文是 AtCoder Beginner Conteset(ABC)380 的总结笔记。
A - 123233 Problem:A - 123233
题目: 给定一个 6 位整数 。判断这个整数内是否刚好出现了 次 1
, 次 2
, 次 3
。
思路: 按照字符串读入,直接排序,看结果和 122333
是否相同即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;void solve1 () { string s; cin >> s; int a = 0 , b = 0 , c = 0 ; for (auto x : s) { if (x == '1' ) a++; if (x == '2' ) b++; if (x == '3' ) c++; } if (a == 1 && b == 2 && c == 3 ) cout << "Yes" << endl; else cout << "No" << endl; } void solve2 () { string s; cin >> s; sort (s.begin (), s.end ()); cout << (s == "122333" ? "Yes" : "No" ) << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve2 (); return 0 ; }
B - Hurdle Parsing Problem:B - Hurdle Parsing
题目: 给定一个字符串 ,仅由 |
和 -
构成。输出两个 |
之间 -
的数量。
思路: 维护一个变量 now
:
当遇到 -
时 now
自增计数;
当遇到 |
时保存 now
的值,并清零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;void solve1 () { string s; cin >> s; vector<int > res; int last = 0 ; for (int i = 1 ; i < s.size (); i++) { int j = i; while (j < s.size () && s[j] != '|' ) j++; res.push_back (j - last - 1 ); i = j; last = j; } for (auto x : res) cout << x << " " ; cout << endl; } void solve2 () { string s; cin >> s; vector<int > res; int now = 0 ; for (int i = 0 ; i < s.size (); i++) { if (s[i] == '|' ) res.push_back (now), now = 0 ; else now++; } for (int i = 1 ; i < res.size (); i++) cout << res[i] << " " ; cout << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve2 (); return 0 ; }
C - Move Segment Problem:C - Move Segment
题目: 给定长度为 的字符串 ,仅由 0
和 1
构成。
把第 个 1
block 移动到第 个 1
block 后面,重新输出字符串。
思路: 解法 1: 按照块来寻找。每次找到当前 1
block 的起点 st
和终点 ed
,同时保存上一个 1
block 的起点 last_st
和终点 last_ed
。数到第 个 1
block 的时候,使用 substr
将字符串重新拼接输出即可。
解法 2: 将原字符串整理到一个 vector<PII>
中。每个 PII
元素同时保存了出现的字符 和 出现的次数。
只需将第 次出现 1
和他前面的元素交换位置,重新输出即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;void solve1 () { int n, k; cin >> n >> k; string s; cin >> s; string res; int last_start = 0 , last_ed = 0 ; int start = 0 , ed = 0 ; int cnt = 0 ; for (int i = 0 ; i < s.size (); i++) { int j = i; while (j < s.size () && s[j] != '1' ) j++; start = j; while (j < s.size () && s[j] == '1' ) j++; ed = j - 1 ; if (cnt == 0 ) { last_start = start, last_ed = ed; } cnt++; if (cnt == k) { res = s.substr (0 , last_ed + 1 ) + s.substr (start, ed - start + 1 ) + s.substr (last_ed + 1 , start - last_ed - 1 ) + s.substr (ed + 1 ); break ; } i = j - 1 ; if (cnt > 1 ) { last_start = start, last_ed = ed; } } cout << res << endl; } void solve2 () { int n, k; string s; cin >> n >> k >> s; s += "." ; vector<PII> v; int now = s[0 ], num = 0 ; for (int i = 0 ; i < s.size (); i++) { if (s[i] == now) num++; else { v.push_back ({now - '0' , num}); now = s[i], num = 1 ; } } int cnt = 0 ; for (int i = 0 ; i < v.size (); i++) { if (v[i].first == 1 ) { cnt++; if (cnt == k) swap (v[i], v[i - 1 ]); } } for (auto x : v) { for (int i = 0 ; i < x.second; i++) cout << x.first; } cout << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve2 (); return 0 ; }
D - Strange Mirroring Problem:D - Strange Mirroring
递归
题目: 给定一个字符串 ,包含大小写字母。
对 执行下面操作 次。
创建字符串 ,是将 中的大小写颠倒。然后将 接到 后面。
进行 次查询:返回 的第 个字母。
约束条件: is a string consisting of uppercase and lowercase English letters, with length between and , inclusive.
and are integers.
思路: 这道题思路很抽象。如下图,以 aBd
为例。
可以发现经过 次操作后,字符串总长度变为了 。
对于查询位置 x
的字符,我们总是能够找到 x
前面距离最近的 ,计算出与他的距离 L
,我们就能推导出它在上一步操作中的位置。以此为递归的依据,最终能够找到它在原始字符串中的位置。
根据记录的跳转次数:
如果是奇数次,则发生大小写转换;
如果是偶数次,则保持原样。
因此,对于任意大的数字,都可以在 的时间复杂度内完成单次查询。
完成 次查询总时间复杂度为 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;string s; int t;char change (char ch) { return ch >= 'a' ? (ch - 32 ) : (ch + 32 ); } char f (LL x, bool is_reverse) { if (x <= s.size ()) { if (is_reverse) return change (s[x - 1 ]); else return s[x - 1 ]; } LL k = s.size (); while (k * 2 < x) k *= 2 ; return f (x - k, !is_reverse); } void solve () { cin >> s >> t; while (t--) { LL x; cin >> x; cout << f (x, false ) << " " ; } cout << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
Problem:E - 1D Bucket Tool
并查集处理区间染色问题。
题目: 有编号 的 个格子排成一行。每个格子的初始颜色为 。
给定 次查询,查询有下面两种情况:
1 x c
:把 x
能到达的所有格子都涂成 c
颜色。
2 c
:打印颜色为 c
的格子的数量。
约束条件:
……
思路: 使用并查集来处理区间染色问题。
并查集在记录连通块的同时,还要维护额外的三个数组值:
区间的左端点 l
区间的右端点 r
集合内部的节点数 cnt
详细参照下面代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int N = 2e6 + 10 ;int fa[N], cnt[N], l[N], r[N];int color[N]; int color_cnt[N]; int n, q;int _find(int x) { return x == fa[x] ? x : fa[x] = _find(fa[x]); } void paint (int x, int c) { x = _find(x); color_cnt[color[x]] -= cnt[x]; color[x] = c; color_cnt[c] += cnt[x]; } void _union(int x, int y) { int fx = _find(x), fy = _find(y); fa[fx] = fy; l[fy] = min (l[fx], l[fy]); r[fy] = max (r[fx], r[fy]); cnt[fy] += cnt[fx]; } void solve () { cin >> n >> q; for (int i = 1 ; i <= n; i++) { color[i] = fa[i] = l[i] = r[i] = i; cnt[i] = 1 ; color_cnt[i] = 1 ; } while (q--) { int op; cin >> op; if (op == 1 ) { int x, c; cin >> x >> c; paint (x, c); int L = l[_find(x)], R = r[_find(x)]; if (color[_find(L - 1 )] == c) _union(L - 1 , x); if (color[_find(R + 1 )] == c) _union(R + 1 , x); } else { int c; cin >> c; cout << color_cnt[c] << endl; } } } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }