AtCoder Regular Contest 059
AtCoder Beginner Contest 043 と同時開催。
k-ashiya-code.hateblo.jp
コンテストページ
解法メモ
E問題
を計算する。
まず、 が定数であると仮定すると、
と分解できる。したがって、各 に対して を について前計算しておく。
次に、動的計画法で、番目までの園児にキャンディーを個配ったときの積の総和 となるように式を立てて実行する。
F問題
小文字 a,b,c,... は0、1のいずれか、B はバックスペースを表すとする。キーボード入力が abcBdBef ならば、エディタに表示されている文字列は abef となるはずである。このとき、a,b,e,f が表す文字列の組み合わせは 通りであり、a,b,e,f としてどの組み合わせが与えられても、abcBdBef の形のキーボード入力は 通りあることがわかる。
N文字の入力でK文字の出力となるような入力の数を と表すことにすると、, , である。
次に、 について、 のときは と の文字列の後ろにBを足せばよいから 。
のときは、 の文字列の後ろにa(0か1)を、 の文字列の後ろにBを足せばよいから 。
は の文字列にaを足せばよいから 。 は の文字列にaを足せばよいから 。
以上のようにして まで求めたあと、 を出力する。
フェルマーの小定理
途中の過程で で割った余りを求めているから、単純に で割ることはできない。そこで、フェルマーの小定理を用いる。
を素数とする。 を で割った余りは1である。
証明はWikipediaに譲る。これを利用すると、 で割ることは をかけて で割った余りを求めることと同値。
二分累乗法
は確実に9桁以上の10進数になるから、ふつうに累乗していこうとするととても時間がかかる。そこで、二分累乗法というテクニックを使う。
まず、求めたい累乗を格納する変数 、底を格納する変数 、指数を格納する変数 を用意する。最初は 、 とする。
が奇数ならば、 に をかけ、 の偶奇によらず を2で割った商に書き換えて、 を2乗する。 が奇数ならば、 に をかけ、…ということを繰り返していけば、かなりの時間短縮になる*1。
プログラム上では2で割るとか偶奇の判断をするとかよりも、ビット演算で1の位のビットが立っていれば掛け算する、 を1つ右シフトする、という操作の方が早いのかもしれない。
*1:線形時間らしいけど本当にそうなのかがわからない。