組み合わせの数をmodで出力するため備忘録
解こうとした問題は以下。190922現在、自分が低支出したコードはTLEになるケースがあり、完全には解けてはいない。
abc042.contest.atcoder.jp
問題は、あるマス目からマス目までの行き方のパターンを出力せよというもので、「答えをそのまま出力すると数が膨大になるため答えを10^9+7で割ったもので出力せよ」と指示がある。
計算数が少ない場合は工夫をせず、を求めて出力すればよいが、そうではない場合があるということである。
詰まったところ
の計算でn,rが大きくなると計算に時間がかかってしまいTLEとなった。
詳しく言うとのn!やr!,(n-r)!が大きくなると計算に時間がかかってしまう。
公式の解説から、注意事項抜粋
- 予めとを計算してテーブルにしておく。
- 計算にはmodを使用し、計算時はそのオーダーに注意する。
- はフェルマーの小定理を使用し、その計算には二分累乗法など、高速な手法が必要である。
そもそもmodとは
以下動画による解説が良い。
【高校数学(発展)】合同式①(modとは何か)【整数】 - YouTube
【高校数学(発展)】合同式②(modの利用)【整数】 - YouTube
これにより、を求めることができる。
プログラムで考えると、modを使うことで以下の利点があると推測する。
- modに使用する数以下の数値が出力されるため計算結果にはオーバフローがない*1
を計算する(フェルマーの小定理と二分累乗法)
次に
フェルマーの小定理によって、
で求めることができる。
しかし、は普通にやったら時間がかかる。
そのため、工夫が必要になり、解決の一つに二分累乗法がある。
二分累乗法の方法はネット上にあふれている。
繰り返し2乗法を使ったべき乗計算 - マツシタのお勉強メモ
二分累乗法による累乗計算プログラミング - swift : R for Radio
残作業
以上の計算方法や計算結果を利用して、組み合わせを求める。
*1:あくまで計算結果。計算途中ではオーバフローする可能性があるため、各計算を行うごとにmodを使って余りを求めておいた方がよい。