jackee777のブログ

情報系学生のつぶやき

diverta 2019 で D を modulo にした人

どうも,diverta 2019 で D 問題の sample 2が 999,999 ずれた人です. (C も分岐対処したつもりが,漏らしてたんですけどね.オーバーフローも初体験で動作を知らなかったし大変だった.)

999,999 ずれるのは半分はオーバーフローのせいです.半分は実装のせいです. (ここ,混乱してます・・・オーバーフローが出ていたが該当箇所を忘れたので修正)

オーバーフローの内容

999,999 ずれますが,最後に加算されたのは 1,000,000 です. オーバーフローして,加算値が 999,999 になってます. (N - i) % i == 0 を 1,000,000 は満たしますが答えの条件には一致してません. 要するに,999,999 ずれている人は 1,000,000 の排除が基本方針です.

このエラーが出た人や,moduloでやったがACでない人の解法は

N = int(input())
 
result = 0
for i in range(1, int(N**0.5)+1):
  if (N - i) % i == 0:
    result += (N - i) / i
 
print(int(result))

なのかなあ.と思います. floor(N/m) = N %m を変形させて,(N - m) % m = 0 かなあと思って解きました. 正規の解法は N = k(m+1) なので正しいように思えますが,この解法は少し間違っているようです(出せばわかる). 薄々気づいていた人もいると思いますが,余剰では k の値が考慮されていないというのが問題です. とりあえず,解決してしまう実装として再度チェック.

N = int(input())
 
result = 0
for i in range(1, int(N**0.5)+1):
  if (N - i) % i == 0:
    temp = (N - i) // i
    if temp != 0 and N // temp == N % temp:
      result += temp
      
print(int(result))

はい,まあ冷静になれば漏れることはあるだろうなあって感じです. これでも AC は取れましたが非常に気持ち悪いです.

漏れる例としては N=9 の時,1, 3, 9 が候補にありますが,答えは8(=9-1)のみです. しかし, (N - i) % i == 0 では,2(=3-1)が答えに浮上します. 他にも,2, 4, 6, 12, 16 等色々なところで,これが起きます. 原因を考えると,(N - i) // i の値が i より大きいときにエラーが起きてます. (小さいケースはfor文の範囲外なので)

で,(N - i) // i > i を N について解くと,N > i ** 2 + i です. これで全部通ります.

N = int(input())
 
result = 0
for i in range(1, int(N**0.5)+1):
  if (N - i) % i == 0 and i ** 2 + i < N:
    result += (N - i) // i
      
print(int(result))

i について解いて,range の範囲を狭めることもできると思いますが それは本気の実装かなんかかなって感じします. i について解くだけなので

import math
N = int(input())
 
result = 0
for i in range(1, math.ceil(((1+4*N)**0.5-1)/2)):
  if (N - i) % i == 0:
    result += (N - i) // i
      
print(int(result))