3匹の猫

みみねこの競プロ精進メモ

AtCoder Beginner Contest 179の感想

「愚直にやると遅いから高速化する!」の考えは大事。

100-200(1)-300-400-500-0で1ペナ5完1500点。

A - Plural Form

文字列を複数形に変換する。文字列の末尾がsかそうでないかで処理が変わる。具体的な処理の流れとしては、入出力を除くと「文字列の末尾の文字を取得」「その文字がsかどうかを判定」「文字列の末尾に文字列を連結」の3つとなる。それぞれの処理の仕方がわからないときは素直にググるべし。

計算量は入出力がボトルネックで、O(|S|)

B - Go to Jail

iに対して、サイコロの目がゾロ目かどうかを保存するboolean型の配列を用意する。この配列の中で、"true"が3個以上続いている箇所を調べたい。この判定は、「今"true"が何個続いているか?」という変数を用意して、前から順番にi番目とi+1番目の値を判定していくとできる。どちらも"true"なら変数の値を1増やし、そうでないなら変数を0にする(0にするのを忘れて1ペナ)。変数の値を0にする直前の値が連続でゾロ目が出た回数なので、この回数が1度でも3以上になったことがあるなら答えはYesとなる。

計算量はO(N)

C - A x B + C

愚直に解くなら、1からNまでの範囲でA, B, Cを回して実際に計算するという方法がとれる。ただしこの方法だと計算量はO(N^3)となりTLEしてしまうので、効率の良い別の解法を考える。

Nが固定されているので、他のもう1文字を固定して考えるとよさそうだと考える。どの文字を固定するかで解法が変わる。

  • Aを固定する場合

この場合、Bを決めれば元の式を変形させることでC = N - A \times Bとなり、Cの値が1パターンに決まる。Cの値は正でないといけないので、0 \lt C = N - A \times Bである。変形するとA \times B \lt N、さらに変形するとB \lt \frac{N}{A}となり、Bの値も一意に決まることがわかる!(不等号を等号に直せばB = \lfloor \frac{N-1}{A}\rfloor となる)
あとはAに関するループを回して総和を取ればよい。計算量は、O(N)

  • Cを固定する場合

式変形するとAB = N-Cとなるので、N-Cの約数がいくつあるかを数えたい。ある整数に対して約数の個数を求めるのにはO(\sqrt{N})の計算量がかかるので、全体ではO(N\sqrt{N})の計算量となり、このままだと間に合わない可能性が高い。ここで、N-Cの値は1からN-1まで連続した値をとるという特徴を利用すると、約数の個数の総和を計算量O(N\log N)で高速に計算することができる。やり方を書こうと思ったけどうまく書けなかったので、これは読者への課題とする…(ググって)
全体の計算量ももちろんO(N\log N)


どちらの方法でもすぐ通せるようならかなり強いと思う。今回はAを固定する方法で通した。

D - Leaping Tak

dp[i] := マスiまで移動する通り数
という風な1次元の動的計画法を考えたいが、移動方法は最大でN通りあるため、普通に書くと計算量がO(N^2)となりTLEする。(公式解説を見ると、実はO(N\log N)でも解けるらしい?)

現在見ているマスをiとすると、入力が区間で与えられることから移動先となりうるマスはある程度固まっていることがわかるので、これを利用する。先ほどの配列dpのほかにもう一つの配列aを用意して、区間の始まりであるa[i+L]dp[i]を足し、区間の終わりであるa[i+R]dp[i]を引く。こうすることで、配列aに対して累積和を前から実行でき、マスiまで見たときのa[i]はまさにマスiまでの遷移方法の通り数となる。

計算量は、O(NK)

E - Sequence Sum

愚直に計算するとO(N)だが、制約が大きいためTLEとなる。より高速な解法を考える。

数列Aの各項はすべてMで割った余りであるので、各項の値は0以上M未満である。さらに数列Aはひとつ前の項に対する漸化式によって定義されているため、同じ値が2回以上登場するなら、そこから周期的にループする。ここで鳩ノ巣原理より、第(M+1)項までに値が重複するので、「第1項から周期に乗るまでの総和」+「周期を繰り返した回数×1周期の項の総和」+「1周できなかった分の余りの総和」が答えとなる。これを求めるには、周期の長さと1周期の総和がわかればよい。

計算量は、O(M)

ちなみにダブリングというテクニックでも解けるらしいがそちらの方はわかりません。一般に、周期に注目して解ける問題はダブリングでも解ける、は正しそうだけど、どうだろうか。

F - Simplified Reversi

解けなかった。愚直に石を置き換える解法だと、空間計算量の時点ですでにO(N^2)かかるため現実的ではない。黒い石で構成された長方形領域を考えるとき、操作を加えても分割される長方形は高々1つだけで、すべてのクエリが終わっても領域の個数はN個ほどしかないな、ということには気づいた。これを使ってうまく解けないか悩んでいたがここでタイムアップ。この発想はかなり近いところまで行ってたようで、例えば縦のラインに白い石が置かれたとき、それより右側の黒い石が置き換えられるのは縦に置くようなクエリが飛んできた時だけなので、そのような列(同様に行も)をメモしておけばよかったっぽい。

終了時のTwitterのTLを見た限りでは、遅延セグ木で解いている人が多そうだった。遅延セグ木がわからないのでもっと精進します。


感想

D問題に少し時間をかけてしまったがしっかり5完できたのはよかった。