AtCoder Beginner Contest 294 に参加しました&反省会
AtCoder Beginner Contest 294 の振り返り
- C問題まで解くことができた
- A問題:入力値が偶数の場合のみ出力する
- B問題:数値からアルファベットに変換する箇所でエラーが発生していると勘違いし時間を浪費した。実際には、ベクターの初期化を怠ったせいだ
- C問題:A,Bの要素がそれぞれCでは何番目かを格納するベクターを用意したが、どちらかの列しか残されない状況で条件分岐させることを気づくのに遅れた
- D問題:呼ばれていない人の集合を管理しようとしたので間違えた
B問題
方針
- 番目の大文字のアルファベットを
char c = 'A' + n - 1
で変換する
解説*1から
- 数字から文字への対応を自分で書くことで文字コードを直接使うことなくこの問題を解くことができる
実装例
#include <iostream> #include <string> using namespace std; string convert = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int main() { int H, W; cin >> H >> W; for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { int x; cin >> x; cout << convert[x]; } cout << endl; } }
C問題
解説*2から
- は、列を連結してソートすることで時間で求めることができる
- が具体的に得られたら、の値からを計算することが 時間やexpected時間で可能
に対する二分探索の実装例
#include <iostream> #include <vector> #include <algorithm> int main() { using namespace std; unsigned N, M; cin >> N >> M; vector<unsigned> A(N), B(M); for (auto &&a : A) cin >> a; for (auto &&b : B) cin >> b; vector<unsigned> C(N + M); merge(begin(A), end(A), begin(B), end(B), begin(C)); for (const auto a : A) cout << lower_bound(begin(C), end(C), a) - begin(C) + 1 << " "; cout << endl; for (const auto b : B) cout << lower_bound(begin(C), end(C), b) - begin(C) + 1 << " "; cout << endl; return 0; }
lower_bound - cpprefjp C++日本語リファレンス
D問題
解説*3から
std::set
のような順序付き集合型を利用する。「受付に呼ばれたが、まだ受付に行っていない人」の集合を管理しながらイベントを処理するcalled
を「受付に呼ばれたが、まだ受付に行っていない人」の集合とする。はじめcalled
は空である。- また、
last
を最後に呼ばれた人の番号とする。便宜上 はじめlast
は とする。 - その後、イベントを順に処理する。イベントの種類に応じて次の処理を行う。
- 種類目のイベントの場合、次に呼ばれるのは
last + 1
である。よってlast
に を足したあとにcalled
にlast
を追加する。 - 種類目のイベントの場合、
x
をcalled
から削除する。 - 種類目のイベントの場合、
called
の最小の要素が答えである。よってこれを出力する。
- 種類目のイベントの場合、次に呼ばれるのは
上記の手順中、called
に関する操作は「要素の追加」「要素の削除」「最小の要素の出力」で、順序付き集合型を用いることで操作をすべて回あたり
で行うことができる。クエリ全体ででこの問題を解くことができる。
実装例
#include <iomanip> #include <iostream> #include <set> #include <vector> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, Q; cin >> N >> Q; set<int> called; int last = 0; while (Q--) { int event; cin >> event; if (event == 1) { called.insert(++last); } else if (event == 2) { int x; cin >> x; called.erase(x); } else { cout << *begin(called) << "\n"; } } }