逆元
MOD
ABC
E
合同方程式
数学
ABC186 E - Throne
https://atcoder.jp/contests/abc186/tasks/abc186_e (opens in a new tab)
水色上位。合同方程式。
解を として、 を求める。 上式は と変形できるため、 下における の逆元が分かれば良い。
を の逆元と定めると、 。分母をはらって
ここで、 の倍数を左辺に加えると( なので合同式的には問題ない)、拡張互除法により が求まる。 の形が見える
本題はここからで、拡張互除法は のほかに を返すが、 のとき、少し話がややこしくなる。( の場合は問題ない)
のとき、 は互いに素でないということだから、一見 の逆元は存在しないように思われるが、 、つまり が で割り切れる場合はその限りでない。
ここで として、 を導入する。 このとき、元の式 は、 となるが、なんと となる。
つまり、 が で割り切れるとき、 を で割り切った値で代用した合同方程式の解 は元の合同方程式 も満たすということである。
具体例をいくつか。 、 、 は で割り切れるため と変形可能 、 、
の下では となるため、拡張互除法を利用して逆元を計算できる。
def extgcd(a, b):
'''
>>> extgcd(a, b)
gcd(a, b), x, y # ax + by = gcd(a, b)
'''
if b == 0:
return a, 1, 0
d, x, y = extgcd(b, a % b)
return d, y, x - a // b * y
t = int(input())
for _ in range(t):
n, s, k = map(int, input().split())
d, k_inv, _ = extgcd(k, n)
if s % d != 0:
print(-1)
else:
print((-(s // d) * k_inv) % (n // d))
余談だが、フェルマーの小定理によって逆元を求めるには が素数である必要があり。今回の問題では直接は使えない。(オイラーのトーシェント関数)