🐢

[鉄則A31] Divisors

2024/05/23に公開

https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ae

数えるのではなく全体から引いて考える問題。

問題を要約する

  • 1..N のなかで 3 または 5 で割り切れるのはいくつある?

何が難しい?

言葉通り 1..N を順番に 3 または 5 で割り切れるか試していくと固まる。

速い解き方

問題を「1..6 を 2 または 3 で割り切れる数を求めよ」に言い換えると、次の o の数が答えになりそうに思える。

1 2 3 4 5 6
2 o o o
3 o o

とりあえず o の数は、

(6 / 2) + (6 / 3)  # => 5

で求まる。

しかし、よく見ると 6 で重複している。一方はいらない。この 6 は 2 * 3 である。つまり 2 * 3 の倍数で重複が起きているので重複個数は、

6 / (2 * 3)  # => 1

で求まる。したがってこの重複分を最後に引けば、

5 - 1  # => 4

辻褄が合う。

単純な実装 (TLE)

N = gets.to_i
ans = (1..N).count do |e|
  e.modulo(3).zero? || e.modulo(5).zero?
end
p ans  # => 5

N が1千万で1秒超える。

解説の模範解答 (AC)

101 ms
N = gets.to_i
p (N / 3) + (N / 5) - (N / (3 * 5))  # => 14

ほとんど何もしてないのに 101 ms とは!?

参考

Discussion