エクサウィザーズプログラミングコンテスト2021(AtCoder Beginner Contest 222)のきろく
エクサウィザーズプログラミングコンテスト2021(AtCoder Beginner Contest 222)参加!
- A - Four Digits (100点)
- B - Failing Grade (200点)
- C - Swiss-System Tournament (300点)
- D - Between Two Arrays (400点)
- E - Red and Blue Tree (500点)
- F - Expensive Expense (500点、実行時間制限: 4 sec)
- G - 222 (600点): 未提出
- H - Beautiful Binary Tree (600点、実行時間制限: 3 sec): 未提出
- 結果、感想
A - Four Digits (100点)
以下なら先頭に0
を追加して...という風にもできますが、やることはゼロ埋め4桁出力なので、printf
やマニピュレータによるフォーマット出力で対応できます。
printf("%04d\n", N);
cout << setw(4) << setfill('0') << N << endl;
B - Failing Grade (200点)
for
文を用いて各 について であるかを調べればいいです。
C - Swiss-System Tournament (300点)
各回毎に前の順位から今回の順位を求まられればいいです。
前回の順位で、上位からどのプレイヤーかが分かれば各試合する組み合わせが分かるので、各プレイヤーがその時点で何勝しているかが分かるので、それを勝数毎のバケツに入れて、各勝数について大きい順に、中のプレイヤーをインデックスの小さい順に取ってやれば、その試合の後の順位が上位から順に求まります。
D - Between Two Arrays (400点)
次のようなDPがまず思いつきます。
として、において についてという遷移で答えが (範囲は で十分) と求まりますが、このままでは として計算量が となってしまうので間に合いません。ここで の部分について累積和を利用することで にでき、これでACをとることができます。
また、 として遷移式を のときにも適応させることで場合分けや初期化を減らすこともできます。
E - Red and Blue Tree (500点)
各辺を通る回数の配列 が求まれば、 として部分和を とするような要素の選び方の数としてDPなどで求まります。
このときのDPは
として、 において についてという遷移で答えを で求めることができます。を求めるのは、DFS等で で求めることができるので、全体として で答えが求まりました。
F - Expensive Expense (500点、実行時間制限: 4 sec)
制約より与えられたグラフは木であることが分かります。全方位木DPで答えは求まるそうですが、私は書けないです。ここでコンテスト終了後に直径を利用する解き方でACしました。
もともとの木に頂点 と の各 について頂点 と を結ぶコスト の辺を追加します。この追加後も木の儘です。頂点 間の距離を と書きます。また、 とします。
ここで頂点の組 が直径をなす、即ち であるように取ります。このとき任意の頂点 について が成立します。
先ずはこれを証明します。
となるような頂点の組 が存在すると仮定します。このとき、 も も や でないことは自明です。また、 のパス上で から最も近い点を とすると となります。
- と の2つのパスが交わらない場合:
より が直径であることに反します。
- と の2つのパスが交わる場合:
のうち、 に近い方が であるように仮定します(そうでない場合は を入れ替える)。このとき となりこちらでも が直径であることに反します。
よってこの二つより、背理法により示したことが示されました。
ここまで来れれば、double-sweep等によって を求め、 の各 について を求めればよいと思ってしまいますが、最初の街では観光しないので、例えば のときは ではなく が答えとなります。
この解き方では4つの始点について最短距離を求めるので や で求めることができます。
G - 222 (600点): 未提出
数式こねくり回したら出来そう
H - Beautiful Binary Tree (600点、実行時間制限: 3 sec): 未提出
難しそう
結果、感想
ちゃっと増加してよかったなっていう感じですが、時間内にFも通したかったなと、ちゃんと精進しないといけないねと思わされました。