整数 A を M で割った余りと、整数 B を M で割った余りが等しい場合、「M を法として A と B は合同である」といい A ≡ B(mod M)と表されます。

mod の逆元

M と互いに素である整数 A に対して、 A × N ≡ 1(mod M) となる 1 以上 M 未満の整数が必ず存在し、これを「mod M での A の mod 逆元」といい、 A^{-1} (mod M) と書きます。

mod の逆元 (paizaランク C 相当)

互いに素である整数 A , M が与えられるので、mod M での A の mod 逆元を求めてください。
ただし、答えは 1 以上 M 未満の整数で出力してください。

入力されるデータ
M A
(ただし 2 ≦ M ≦ 100,000
2 ≦ A ≦ 100,000
M と A は互いに素 )

逆元を求めたいときはどうすればよいのでしょうか?

x, y についての 1 次方程式 Ax + My = 1 の 解 x が A の 逆元です。gcd(A, M) = 1 であるので、この方程式の解 x は拡張ユークリッドの互除法を用いることで求めることができます。

mod の累乗

競技プログラミングの問題のなかには「答えの値は非常に大きな値になることがあるので 10^9 + 7 で割ったあまりを出力してください」と書かれているものがあります。mod の累乗の高速な計算をしたいときはどうすればよいのでしょうか?

高速な累乗の計算 (paizaランク C 相当)

整数 A , B , M が与えられるので、 A^B(mod M) を求めましょう。

A B M
(ただし、1 ≦ A, B, M ≦ 100,000)

最大 100,000 乗を考えなければならないのでループを回していては時間が足りません。実際には100,000回程度のループであれば間に合うのかもしれませんが、繰り返し二乗法を使えば累乗指数がもっと大きな数になっても対応できます。

まず b の 2 進数表現を考える。b の最下位の桁が 1 かどうかを確認する。
最下位の桁が 1 の場合、a を ans にかける。
そのあと、a を a の 2 乗に置き換え、b を右に 1 ビットシフトする(つまり 2 で割る)。

この方法ならmod の累乗を高速に計算することができます。

mod の階乗

No.502 階乗を計算するだけ

整数 n が与えられる。n! mod (10^9 + 7)を答えよ。

入力されるデータ
n
(ただし 0 ≦ n ≦ 10^18)

普通に階乗を計算しようとすると計算量はO(n)になります。そのため n ≦ 10^18 という条件があると間に合いません。

もし n が 10^9 + 7 以上の場合は n! は 10^9 + 7 の倍数となり、n! ≡ 0 mod (10^9 + 7)となります。では n が 10^9 + 7 未満で比較的大きな値の場合はどうやって計算量を減らせばよいでしょうか?

もし n = 900000006 の場合、n = 900000000 のときの n! mod (10^9 + 7) の値がわかっていればこの値を利用して処理を高速化することができます。

若干時間がかかりますが、事前に以下のようなコードを実行して答えを出力しておきます。

すると以下のような出力が得られました。

この値を利用して以下のようなコードを書きます。