繰り返し二乗法

・x**yを使わないといけないのに、yの制約が「0≦y≦10**9」とかのとき。

①"aのn乗"の計算

def reppow(a,n):
  if n == 0:
    return 1
  if n == 1:
    return a
  if n%2 == 1:
    ret = reppow(a,n-1)*a
    return ret
  ret = reppow(a,n//2)
  ret = ret*ret
  return ret

このままgoogle colabなどで

reppow(3,100000)

で実行(して、結果を表示)しようとすると

ValueError: Exceeds the limit (4300) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit

となってしまう。

import sys
sys.set_int_max_str_digits(10**6)

これで解決。
ただし、この桁数をそのまま競プロで使うことはなさそうなので、なにかしらのmodを取るような設問にはなりそう。
逆に、4300桁で収まるくらいなら繰り返し二乗法でなくても良い程度の計算量に収まりそう。


②"aのn乗をpで割ったあまり"の計算

import sys
sys.setrecursionlimit(10**9)

def modpow(a,n,p):
  if n == 0:
    return 1
  if n == 1:
    return a%p
  if n%2 == 1:
    ret = modpow(a,n-1,p)*a
    return ret%p
  ret = modpow(a,n//2,p)
  ret = ret*ret
  return ret%p

pypyなら、

import pypyjit
pypyjit.set_param('max_unroll_recursion=-1')

も忘れずに追加しておく。