Atcoder ABC 146 の記録
Atcoder 146 の C問題で出された二分探索について復習していきたいと思います。
二分探索とは
まずはそもそも二分探索ってなんだっけ?というところから振り返ります。
Wikipediaによると、
二分探索(にぶんたんさく、英: binary search、BS)やバイナリサーチとは、ソート済み配列に対する探索アルゴリズムの一つ。
二分探索 - Wikipedia
ということでポイントは、ソートすること、配列にすることですね。
二分探索をしたいとき
二分探索をしたいときとはどのようなときでしょうか?
今の理解だとふんわりこんな感覚で捉えています。
- 総当りで何かの値を探したいとき。
- データ量が多くて線形探索(1から値を見ていく)は使いたくない、使えないとき。
- 総当りする対象がソートできそうなとき。(intでもstrでも)
どういう仕組み?
すみません。他の記事を参照ください。。
- 最初に見る
- わかりやすい解説
- 文字列でソートした配列を二分探索する
pythonによる実装
20個のランダムな数字の配列を作り、その中からランダムな数字ひとつの位置を導出する処理を書いてみました。
import random array = [random.randint(0,1000) for i in range(20)] search = array[0] array.sort() l = -1 r = 20 while abs(l-r) != 1: mid = abs(l+r)//2 print('array:', array,'/ search:',search,'/ mid:',mid,'/ l:',l,'/ r:',r) if search < array[mid]: l = mid elif search >= array[mid]: r = mid print(array[mid],mid)
動かしてみるとどういう動きをするのか追えると思います。
//1回目 array: [11, 29, 75, 79, 153, 187, 308, 371, 375, 384, 398, 425, 565, 598, 667, 713, 778, 803, 807, 820] / search: 778 / mid: 9 / l: -1 / r: 20 array: [11, 29, 75, 79, 153, 187, 308, 371, 375, 384, 398, 425, 565, 598, 667, 713, 778, 803, 807, 820] / search: 778 / mid: 4 / l: -1 / r: 9 array: [11, 29, 75, 79, 153, 187, 308, 371, 375, 384, 398, 425, 565, 598, 667, 713, 778, 803, 807, 820] / search: 778 / mid: 1 / l: -1 / r: 4 array: [11, 29, 75, 79, 153, 187, 308, 371, 375, 384, 398, 425, 565, 598, 667, 713, 778, 803, 807, 820] / search: 778 / mid: 0 / l: -1 / r: 1 11 0 //2回目 array: [5, 121, 138, 231, 231, 294, 296, 312, 384, 414, 450, 476, 486, 551, 555, 580, 633, 639, 721, 781] / search: 121 / mid: 9 / l: -1 / r: 20 array: [5, 121, 138, 231, 231, 294, 296, 312, 384, 414, 450, 476, 486, 551, 555, 580, 633, 639, 721, 781] / search: 121 / mid: 14 / l: 9 / r: 20 array: [5, 121, 138, 231, 231, 294, 296, 312, 384, 414, 450, 476, 486, 551, 555, 580, 633, 639, 721, 781] / search: 121 / mid: 17 / l: 14 / r: 20 array: [5, 121, 138, 231, 231, 294, 296, 312, 384, 414, 450, 476, 486, 551, 555, 580, 633, 639, 721, 781] / search: 121 / mid: 18 / l: 17 / r: 20 array: [5, 121, 138, 231, 231, 294, 296, 312, 384, 414, 450, 476, 486, 551, 555, 580, 633, 639, 721, 781] / search: 121 / mid: 19 / l: 18 / r: 20 781 19
ABC 146 C - Buy an Integer
整数屋さん。
ABC146当日は、この問題を見て二分探索を使えば解けることにすぐ気づかなかったんですよねー。
最大値を求める=式の条件を満たす値を探すという思考が無かったんですね。
a, b, x = map(int,input().split()) l = -1 r = 10 ** 9 + 1 ans = 0 while abs(l-r) != 1: n = abs(l+r)//2 tmp = a * n + b * len(str(n)) if tmp == x: ans = n break elif tmp < x: l = n ans = n elif tmp > x: r = n print(ans)
雑記
作者はてんぷら(@tempura_cpp)さんという方ですね。
Cは二分探索の基本的な問題だろうと思って作った(算数を頑張るとか定数倍高速化を頑張るとかは好きにしてほしい)んですけど、令和ABCのC最難候補の1つになってしまった(どうして…。)
— てんぷら (@tempura_cpp) 2019年11月24日
まとめ
手軽にブログ投稿がんばるぞ。