👋
ABC186/E - Throne
問題
自然数
次を満たす最小の自然数
ただし
解法
公式では互除法で解いてる.
今からここで書こうとするのは
これが全て.
N 以下であることについて
答えが
を考える.
問題はこれが初めて
もし
しかもとり得る値が
従って
Baby-Step Giant-Step
自然数
0 \sqrt{N} + 0 0 \sqrt{N} + 1 0 \sqrt{N} + 2 \vdots -
,0 \sqrt{N} + \sqrt{N} 1 \sqrt{N} + 0 1 \sqrt{N} + 1 1 \sqrt{N} + 2 \vdots -
,1 \sqrt{N} + \sqrt{N} \vdots (\sqrt{N}-1) \sqrt{N} + 0 (\sqrt{N}-1) \sqrt{N} + 1 (\sqrt{N}-1) \sqrt{N} + 2 \vdots -
.(\sqrt{N}-1) \sqrt{N} + \sqrt{N}
ただしここで
よく見ると上の式は重複が含まれてるんだけど, 小さい順に網羅して調べることが大事なので, そこはとやかく言わないことにする.
さて
を調べれば良い.
擬似コードで書くと
r = sqrt(m);
for i in range(0, r) {
for j in range(0, r) {
if (S + i * r * K + j * K) % N == 0 {
yield i * r + j;
}
}
}
この range
は両端を含む範囲だとする.
この二重ループをそのまま実行すると, 結局 j
についてだけ次のように先にまとめておく.
d = {} // set
for j in range(0, r) {
d.insert((j * K) % N);
}
こうしておけば, 各 i
について
を満たす
d
にあるかを問い合わせれば良い.どうせ mod を取るので,
d
には予め mod を取った値で入れておくのが良い.式変形をして,
と出来るので, これが
d
に含まれるかを見ればいい.d
をハッシュテーブルとか二分探索木で持っておけばここは高速に可能.
また, いま問題になってるのは, 存在するかどうかだけではなくて, 存在する場合のその添字
d
はただの集合じゃなくて, それを実現する i
の値まで持っておくとよい.
HashMap とか BTreeMap とかそういう辞書にする.
d = {} // dict
for j in range(0, r) {
x = (j * K) % N;
if x not in d {
d[x] = j;
}
}
d[x]
は
for i in range(0, r) {
y = (S + i * r * K) % N;
x = N - y; // y + x = 0 を満たす x
if x in d {
m = i * r + d[x];
print(m);
return;
}
}
// 見つからなかった
print(-1);
これで d
の問い合わせの時間がここにさらに掛かる).
Discussion