トヨタ自動車プログラミングコンテスト2024#12(AtCoder Beginner Contest 384)に参加しました。
結果
A~E問題の5問正解でした。
久々にE問題まで解けた気がする。
F問題はくらいの解き方は思いついたけど、そこから早くする方法が見つからなかった。
A - aaaadaa
文字列が与えられるのでc1以外の文字をc2に置き換えて出力する問題。
文字列を1文字ずつ取り出したり、if文で判定できたりが使えれば解ける問題。
B - ARC Division
N回コンテストを受けるので最終的にレーティングがいくつになっているかを答える問題。
現在のレーティングとコンテストの種類、そのコンテストでのレーティングの増減量が与えられるので、 コンテストを受ける時点でのレーティングをもとにそのコンテストでレーティングが変化するかどうかを判定して新しいレーティングを計算する。っていうのをN回繰り返す。
ループの中で、
- 現在のレーティングだと今回のコンテストでレーティングが変化するかどうかの判定
- 新しいレーティングの計算
が正しく実装できれば解ける問題。
C - Perfect Standings
A~E問題の5問の配点が与えられるので、このコンテストで取りうる点数の高い順にどの問題を解けば良いかを 出力する問題。点数が同じ時は解く問題セットの文字列を辞書順に並べる。
要するに点数別回答問題別にソートして順番に出力する問題。問題の解き方は全32通りで全問解かないの1通りは出力対象外(といってもAtCoderの仕様上最後に空文字を出力すると無視してくれるので空白行を最後に出力しても大して問題はない)。
どうやって32通り全通りを検証するかを考えるのがポイントなのかなと思う。
私はbit全探索で全通り確かめて、点数別に解いた問題セットの文字列をsetに入れて
点数が高い方から順にsetの文字列を出力していって解いた。
たぶん、点数と解いた問題セットの文字列をpairにして、点数を昇順、文字列を降順にソートできればvectorに入れてソートするだけで解ける。
自分でソート時の大小をboolで返す関数を作って、それでソートさせられれば実装できるけど、何かが間違っていてエラーが解消できなかった。
D - Repeated Sequence
周期Nの数列Aの先頭N項が与えられる。この周期Nの数列の部分列のうち、総和がSとなる部分があるかどうかを答える問題。
総和がSとなる部分列なので、典型的な尺取法の問題。
第N項までの和を求めておけば、Sが総和以上の場合には何周期かをまたがった部分列だと判断できる。
総和以下になるまでSから総和を引いていけば(=総和でSのmodを取れば)、周期Nいくつ分かを丸々省略できるようになる。
1周目の後半から2周目の前半の部分列が正解のパターンを考慮して、 長さ2Nの数列に対して尺取法で部分列がSとなるかを探索していき、答えれば解ける。
この考慮が漏れていて6WAだった…
コンテスト後にSNSを見るとこの6WAが解消できなくて、でも原因がわからないと嘆いている人がそこそこいた。
意外と気づかないハマるポイントなのかなあ。
E - Takahashi is Slime 2
H✕Wのマス目があり、各マスに強さが設定されている。
指定された座標が開始時の強さで、隣接するマス目の強さが自分の強さの未満の時、そのマスを吸収して更に隣接したマスが吸収できるようになる。
吸収すると自分の強さは吸収したマスの強さ分大きくなる。
この設定の時自分はどれだけ強くなれるかを答える問題。
明らかに強さが小さいマスから吸収していった方が良い。
また、吸収するマスの強さ/Xとわり算をして大小比較をすると小数点以下の誤差が原因で正確に計算できないかも知れないと思ったので式変形してマス目の強さ✕Xが現在の強さ未満かどうかで判定した。
また、数字が大きいとオーバーフローするかもしれないなと思ったのでこの比較時にはdoubleに型変換してから比較した。
強さが小さいマスから処理したいので優先度付きキューを使って現在隣接しているマスとそのマスの強さを管理していった。
要するに、候補の中から強さの弱い順に探索する幅優先探索でシミュレートして解いた。