等比数列の和の公式が使えるか
問題は、 の を求めよというものです。
これは等比数列の和の公式から となり、 を計算すればよいように思えます。
この計算は、 と を求めて掛け合わせる計算になります。
は の逆元で、
を満たす のことです。これが求められるのは と が互いに素 (最大公約数が 1) の場合のみです。互いに素でなく最大公約数が の場合、 は常に の倍数で、 1 になることがないためです。
そのため、 と が互いに素の場合は等比数列の和の公式で答えを出すことができますが、互いに素でない場合は公式は使えません。
ダブリングを用いた計算
を計算する場合、 と大きな値になる可能性があるため、ひとつずつ計算しては時間がかかりすぎます。
そこで、項数を倍々にした和を考えます。最初の 1 から までの 項の和を と表します。
ここから を求めると、
となることから、 と合わせて を が小さいほうから順に 計算していくことができます。
ここから を求めるには、例えば のとき次のように計算します。
コード例 (Julia)
function solve() # 入力 readInts() = parse.(Int,split(readline())) readInt() = parse(Int,readline()) A, X, M = readInts() n = Int(ceil(log(2,X))) AP = zeros(Int64, n+1) AP[1] = 1 # A^0 = 1 p = A # A^(2^0) for i = 1:n AP[i+1] = ((p * AP[i])%M + AP[i])%M # 1 + A + A^2 + ... + A^(2^(i)-1) p = (p * p)%M # A^(2^i) end k = X q = A ans = 0 for i = 1:n+1 if k % 2 == 1 ans = ((q * ans)%M + AP[i])%M end q = (q * q) % M k = div(k,2) end println(ans) end # function solve # main solve()