D - Christmas Trees 解説
by
kemuniku
Pythonのrangeを使う解法
Pythonのrange
オブジェクトと、二分探索を行う標準ライブラリであるbisect
を用いる解法を紹介します。(bisect
モジュールを知っていることを前提とします。)
まず、この問題を二分探索で解くことを考えます。\(A+kM\)と表されるような地点は無数にありますが、今回の問題では\(L,R\)が\(-{10}^{18}\)から\({10}^{18}\)であることから、この範囲の条件を満たす座標をすべて配列に昇順に記録します。
このとき答えは(この配列に含まれるR以下の個数) - (この配列に含まれるL未満の個数)
と表すことができ、先ほど作った配列を\(X\)とすると
bisect_right(X,R)-bisect_left(X,L)
のように計算することができます。
上記の解法で問題となるのが配列\(X\)の要素数が最大で\(2 \times {10}^{18} + 1 \)個になってしまうことで、これを実際にlist
などで持つのは現実的ではありません。
ここで、Pythonのrange
オブジェクトを用います。Pythonのrange
オブジェクトは等差数列を管理するシーケンス型であり、ランダムアクセスが可能です。内部では開始地点と終了地点、ステップの値を持っているだけなので、大きな等差数列について大きなメモリ空間を使うことなく管理することができます。
また、Pythonのbisect
モジュールは、len()
でのサイズの取得ととランダムアクセスが可能ならば二分探索を行うことができます。
よって、配列\(X\)をrange
オブジェクトとして管理して、bisect
モジュールで二分探索をすることで、この問題を解くことができます。
range
オブジェクトのサイズを大きくしすぎる(\(2^{63}\)以上)とlen()
を呼んだときにOverflowError
が発生してしまいREとなってしまう点に注意してください。
実装例(Python)
from bisect import bisect_left,bisect_right
A,M,L,R = map(int,input().split())
X = range(A-(2*10**18)*M,10**18+1,M)
print(bisect_right(X,R) - bisect_left(X,L))
投稿日時:
最終更新: