G - Kyoen Editorial
by
kyopro_friends
おまけ:有理素数のガウス素数への高速な分解
次の問題を考えます。
\(N\) 以下の素数 \(p\) 全てに対して、\(a^2+b^2=p\) を満たす正整数の組 \((a,b)\) を求めよ。
ナイーブな全探索により \(O(N^{1.5})\) で求めることができます。以下では \(O(N\log N)\) で求める方法を説明します。
\(O(N\log N)\) の前計算により、 \(N\) 以下の数の素因数分解は \(O(\log N)\) でできるとしてよいです。(参考)
\(p\) の昇順に計算します。
まず、\(x^2+1\equiv 0 \mod p\) となる \(x\) を以下の手順で見つけます。
- 整数 \(y\) をランダムに取り、\(x=y^{(p-1)/4} \bmod p\) とする。\(x^2+1\equiv 0 \mod p\) でなければ \(y\) を選び直す。
\(y\) をランダムに取るとき、目的のものが得られる確率は \(1/2\) なので、この操作は \(O(1)\) 回のやり直しで済みます。
この \(x\) を用いて \(x^2+1=kp\) とすると \(k<p\) なので \(k\) のガウス整数の範囲での因数分解は既知であり、左辺の \((x+\sqrt{-1})(x-\sqrt{-1})\) を適当に割ることで、\((a+b\sqrt{-1})(a-b\sqrt{-1})=p\) を得ることができます。
擬似コード
gauss_divisor = {}
def get_x(p):
while True:
y = random_int()
x = modpow(y, (p-1)/4, p)
if (x*x+1) % p == 0:
return x
for p in primes:
if p == 2:
gauss_divisor[2] = 1+i
else if p % 4 == 3:
gauss_divisor[p] = p
else:
x = get_x(p)
k = (x*x+1) / p
g = x+i
# g*conjugate(g) = k*p
for q in prime_factor(k):
qg = gauss_divisor[q]
if (g*qg) % q == 0:
g = g*qg / q # g /= conjugate(qg)
else:
g = g*conjugate(qg) / q # g /= qg
gauss_divisor[p] = g
posted:
last update:
