Educational Codeforces Round 53 参加記録&解説(A~D)
Dashboard - Educational Codeforces Round 53 (Rated for Div. 2) - Codeforces
4完で256位。キリ番です(?)
Div2オンリーならもっと上を目指したいところ…
A. Diverse Substring
問題概要
長さ の英小文字列 が与えられる。 の連続部分文字列 であって、以下の条件を満たすものを1つ求めよ。あるいはそれが存在しないことを判定せよ。
- に含まれるどのアルファベットも、それが に含まれる個数は を超えない。
制約
- は英小文字からなる
解法
を「超えない」ということは、ちょうど半分はOKということです。なので、隣接する2文字が異なる箇所が に存在すれば、その2文字は答えになります。
もし隣接する2文字が異なる箇所がない場合、全ての文字が同じだということなので、その場合答えは存在しません。
ACコード
(C++)Submission #44846895 - Codeforces
B. Vasya and Books
問題概要
冊の本が積み上げられている。上にあるものから順に、相異なる の番号が付いている。
以下の操作を 回行う。
- 取り出したい本の番号 が与えられる。この番号は操作ごとに相異なる。
- その本が積み上げられた本の中に存在する場合、その本とその本より上にある本を全て取り出す。
- その本がもう取り出し済みである場合、何もしない。
各操作において取り出される本の数を求めよ。
制約
- であり、これらは相異なる
- であり、これらは相異なる
解法
は「上から 番目の本の番号はいくつか」という情報ですが、これを「番号 の本は上から何番目にあるか」という情報に変換しておきます。
各操作を処理する際には、今まで上から何冊の本を取り出したかを記憶しておきます。本の番号 からその本の位置が分かれば、追加で何冊本を取り出さなければいけないかが求められます。
ACコード
(C++)Submission #44851092 - Codeforces
C. Vasya and Robot
問題概要
座標平面にロボットがいる。初期位置は 、目的地は である。
ロボットの動く方向(UDLR
)を示す 文字の文字列 が与えられる。この文字列に以下のような変更をして、 回の動作完了後にちょうどロボットが目的地にいるようにしたい。
- の0文字以上の連続部分文字列を選択する。その中の文字それぞれを
UDLR
のうち好きなものに変更する(変更しない文字があってもよい)。
選択する連続部分文字列の長さを最小にしたい。その長さを求めよ。(どうやっても目的地にたどり着けない場合はそれを判定せよ)
制約
- の各文字は
UDLR
のいずれかである
解法
まず、目的地に到達不可能である条件を考えます。 として、
- である(届かない)
- と の偶奇が異なる(ぴったり止まれない)
のどちらかを満たす時、到達不可能です。以降、到達可能である場合を考えます。
「連続部分文字列を選んでその中を変更する」ということは、裏返すと「左から○文字と、右から○文字は変更しない」ということです。どちらかの「変更しない文字数」を固定してみます。
「左から 文字目までを変更しないと決めた時、 文字目から何文字目までを変更すれば目的地に到達可能か?」という問題を考え、その最小値を とします。そうすると が増加するにつれて も(広義)単調増加するため、しゃくとり法を使うことができます。
可能/不可能の判定においては、「変更しないと決めた文字だけでどこまで移動するか」を計算して、その到達点から目的地までの距離を計算します。自由に変更できる文字数がその距離以上であれば、(偶奇の判定は済ませているので)目的地に到達可能です。
しゃくとり法を行う上で必要な「区間に含める」「区間から除く」操作も、「変更しないと決めた文字でどれだけ移動するか」を1文字分足し引きすればよいので可能です。
ACコード
D. Berland Fair
問題概要
軒の店が円形に並んでいて、 番目の店はキャンディを1個 円で売っている。
ポリカープは最初に 円持っており、以下のようにキャンディを買う。
- 1番目の店から順番に訪れる。
- 訪れた店で、キャンディを1個買うお金があれば1個買う。その後、次の店に移動する。( 番目の次は1番目に移動する)
- どの店でもキャンディを買えなくなったら終了する。
ポリカープが買うキャンディの個数を求めよ。
※お金の単位は勝手に円にしました。burlesってどこのお金の単位なんでしょうね…?
制約
解法
この問題はいろいろ解法があるみたいですが…私が解いたときのものを書きます。ちょっと面倒ですが、計算量の見積もりは楽です。
まず最初の状態において「全ての店でキャンディを購入する周回を何周できるか?」を考えます。全ての店のキャンディの価格合計を とします。 であるとき、 として全ての店のキャンディを 個買うことができます。所持金は 円減り、キャンディを 個入手し、1番目の店に戻ってきます。
その後、次の周回でキャンディを買おうとすると、どこかの店でキャンディを買えなくなります。所持金が増えることはないので、その店では今後1つもキャンディを買えず、通過するだけになります。そのため、この店を消してしまうことを考えます。
店を1つ消すと、1周あたりのキャンディの価格合計が減り、キャンディの個数も減ります。その状態で改めて「全ての店でキャンディを購入する周回を何周できるか?」を考えることができます。これを全てのお店が消えるまで繰り返すことで、答えを求めることができます。
この解法において必要なのは「どの店でキャンディを買えなくなるか」を判定することと、「その店を消す」ことの2つです。これはすなわち、
- 操作途中の所持金 について、 となる最小の を求める。
- ある要素 の値を0にする。
の2つの操作であり、これはBITでデータを保持し二分探索を行うことで実現できます。
BITでの二分探索は、毎回独立に合計クエリを処理していると全体計算量が になりますが、上手くやると にできます。今回の制約だと で十分間に合いました。
ACコード
(C++)Submission #44869480 - Codeforces
本番コード。これは です。
(C++)Submission #44911558 - Codeforces
も書いてみました。