AT274の技術だったりなかったり

あっとのTECH LOG

競プロのこととか技術のこととか。たまに日常を書きます。

ABC161 F - Division or Substraction

問題原文

atcoder.jp

問題要旨

正整数  N が与えられる。2以上  N 以下の整数  K を決めて、  N < K となるまで以下の操作を繰り返す。

  •  N % K == 0 なら、  N を \frac{N}{K} で置き換える。そうでないなら、  N - K で置き換える。

最終的に  N が1になるような  K はいくつあるか?

  •   1 \leq N \leq 10^{12}

解法

本番は実験の結果通してしまった。解説PDFがすごいわかりやすい。
まず、 割り算をしない場合、  N mod K は変化しない
つまり、最終的に 1 になるためには、  N mod K = 1 であればよい。 そしてそのような  K は、1以外の  (N - 1) の約数。(N / K = x あまり 1などとして式変形すればわかる)

また、1回以上割り算が起こるような  K は、  N の約数。
これらについては実際に操作を行って判定しても十分間に合う。

実装

最後に一応集合をとっているけど、  N N - 1 は互いに素だからしなくていいらしい。
 N N - 1 が2以上の共通の約数  xを持つと仮定すると、  N N - 1 x の倍数ということになる。 x の倍数と  x の倍数の差は  x の倍数だが、  N - (N - 1) = 1 になって、これは仮定に矛盾する。)

N = int(input())

ans = []
for n in range(1, int(N ** 0.5) + 1):
    if (N - 1) % n == 0:
        ans.append(n)
        ans.append((N - 1) // n)

for k in range(2, int(N ** 0.5) + 1):
    if N % k != 0:
        continue

    x = N
    while x % k == 0:
        x //= k

    if x % k == 1:
        ans.append(k)

print(len(set(ans)))

感想

ノリで通してしまったけど、すごい学びが多い問題だった。
時間を空けてちゃんと証明して解きなおしたいな。