DevLog πŸ“¨/Baekjoon

[DevLog][Baekjoon] 8983: 사λƒ₯κΎΌ

cece00 2023. 8. 16. 15:37

01) 문제

KOI 사λƒ₯ν„°μ—λŠ” N 마리의 동물듀이 각각 νŠΉμ •ν•œ μœ„μΉ˜μ— μ‚΄κ³  μžˆλ‹€. 사λƒ₯터에 온 사λƒ₯꾼은 일직선 상에 μœ„μΉ˜ν•œ M 개의 μ‚¬λŒ€(총을 μ˜λŠ” μž₯μ†Œ)μ—μ„œλ§Œ 사격이 κ°€λŠ₯ν•˜λ‹€. νŽΈμ˜μƒ, 일직선을 x-좕이라 κ°€μ •ν•˜κ³ , μ‚¬λŒ€μ˜ μœ„μΉ˜ x1, x2, ..., xM은 x-μ’Œν‘œ 값이라고 ν•˜μž. 각 동물이 μ‚¬λŠ” μœ„μΉ˜λŠ” (a1, b1), (a2, b2), ..., (aN, bN)κ³Ό 같이 x,y-μ’Œν‘œ κ°’μœΌλ‘œ ν‘œμ‹œν•˜μž. λ™λ¬Όμ˜ μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λͺ¨λ“  μ’Œν‘œ 값은 μ–‘μ˜ μ •μˆ˜μ΄λ‹€.

사λƒ₯꾼이 가지고 μžˆλŠ” 총의 사정거리가 L이라고 ν•˜λ©΄, 사λƒ₯꾼은 ν•œ μ‚¬λŒ€μ—μ„œ 거리가 L 보닀 μž‘κ±°λ‚˜ 같은 μœ„μΉ˜μ˜ 동물듀을 μž‘μ„ 수 μžˆλ‹€κ³  ν•œλ‹€. 단, μ‚¬λŒ€μ˜ μœ„μΉ˜ xi와 λ™λ¬Όμ˜ μœ„μΉ˜ (aj, bj) κ°„μ˜ κ±°λ¦¬λŠ” |xi-aj| + bj둜 κ³„μ‚°ν•œλ‹€.

예λ₯Ό λ“€μ–΄, μ•„λž˜μ˜ κ·Έλ¦Όκ³Ό 같은 사λƒ₯ν„°λ₯Ό 생각해 보자. (μ‚¬λŒ€λŠ” μž‘μ€ μ‚¬κ°ν˜•μœΌλ‘œ, λ™λ¬Όμ˜ μœ„μΉ˜λŠ” μž‘μ€ μ›μœΌλ‘œ ν‘œμ‹œλ˜μ–΄ μžˆλ‹€.) 사정거리 L이 4라고 ν•˜λ©΄, μ μ„ μœΌλ‘œ ν‘œμ‹œλœ μ˜μ—­μ€ μ™Όμͺ½μ—μ„œ μ„Έ 번째 μ‚¬λŒ€μ—μ„œ 사λƒ₯이 κ°€λŠ₯ν•œ μ˜μ—­μ΄λ‹€.

8983

μ‚¬λŒ€μ˜ μœ„μΉ˜μ™€ λ™λ¬Όλ“€μ˜ μœ„μΉ˜κ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, μž‘μ„ 수 μžˆλŠ” λ™λ¬Όμ˜ 수λ₯Ό 좜λ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

μž…/좜λ ₯

μž…λ ₯의 첫 μ€„μ—λŠ” μ‚¬λŒ€μ˜ 수 M (1 ≀ M ≀ 100,000), λ™λ¬Όμ˜ 수 N (1 ≀ N ≀ 100,000), 사정거리 L (1 ≀ L ≀ 1,000,000,000)이 λΉˆμΉΈμ„ 사이에 두고 주어진닀. 두 번째 μ€„μ—λŠ” μ‚¬λŒ€μ˜ μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” M개의 x-μ’Œν‘œ 값이 λΉˆμΉΈμ„ 사이에 두고 μ–‘μ˜ μ •μˆ˜λ‘œ 주어진닀. 이후 N개의 각 μ€„μ—λŠ” 각 λ™λ¬Όμ˜ μ‚¬λŠ” μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ’Œν‘œ 값이 x-μ’Œν‘œ κ°’, y-μ’Œν‘œ κ°’μ˜ μˆœμ„œλ‘œ λΉˆμΉΈμ„ 사이에 두고 μ–‘μ˜ μ •μˆ˜λ‘œ 주어진닀. μ‚¬λŒ€μ˜ μœ„μΉ˜κ°€ κ²ΉμΉ˜λŠ” κ²½μš°λŠ” μ—†μœΌλ©°, λ™λ¬Όλ“€μ˜ μœ„μΉ˜κ°€ κ²ΉμΉ˜λŠ” κ²½μš°λ„ μ—†λ‹€. λͺ¨λ“  μ’Œν‘œ 값은 1,000,000,000보닀 μž‘κ±°λ‚˜ 같은 μ–‘μ˜ μ •μˆ˜μ΄λ‹€.

좜λ ₯은 단 ν•œ 쀄이며, μž‘μ„ 수 μžˆλŠ” λ™λ¬Όμ˜ 수λ₯Ό μŒμˆ˜κ°€ μ•„λ‹Œ μ •μˆ˜λ‘œ 좜λ ₯ν•œλ‹€.

4 8 4
6 1 4 9
7 2
3 3
4 5
5 1
2 2
1 4
8 4
9 4
# output is 6

μ„œλΈŒνƒœμŠ€ν¬

번호 배점 μ œν•œ
1 9 M ≀ 10, N ≀ 10, X ≀ 10
2 14 M ≀ 20, N ≀ 20, X ≀ 20
3 18 M ≀ 100, N ≀ 100
4 19 M ≀ 2,000, N ≀ 2,000
5 40 좔가적인 μ œμ•½ 쑰건은 μ—†λ‹€.

02) 풀이

각 μ‚¬λŒ€μ— λŒ€ν•΄ 사정거리 μ•ˆμ˜ λ™λ¬Όμ˜ 수λ₯Ό 각각 κ΅¬ν•œ λ‹€μŒ 쀑볡을 μ œκ±°ν•΄μ£ΌλŠ” 접근을 λ¨Όμ € λ– μ˜¬λ ΈλŠ”λ°, 쀑볡 제거 κ³Όμ •μ˜ κ΅¬ν˜„λ°©λ²•μ΄ 잘 μƒκ°λ‚˜μ§€ μ•Šμ•˜λ‹€. κ·Έλž˜μ„œ 각 점의 μž…μž₯μ—μ„œ μ‚¬λŒ€μ˜ 사정거리 μ•ˆμ— ν¬ν•¨λ˜λŠ”μ§€μ˜ μ—¬λΆ€λ₯Ό μ²΄ν¬ν•œ λ‹€μŒ, μ–΄λ–€ ν•œ μ‚¬λŒ€μ˜ 사정거리에도 ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μ œμ™Έν•  점으둜 μΉ΄μš΄νŒ…ν•΄μ£Όλ„λ‘ ν–ˆλ‹€.

M, N, L # 각각 μ‚¬λŒ€μ˜ 개수, 동물(점)의 개수, 사정거리
m = list[int    0 .. M-1] # μ‚¬λŒ€μ˜ μ’Œν‘œ λ°°μ—΄
n = list[[x, y] 0 .. N-1] # 점의 μ’Œν‘œ λ°°μ—΄

excp = 0  # μ œμ™Έν•  점의 개수
for i in range(N):
  if 사정거리 μ•ˆμ— μ—†μŒ:
    excp += 1
    ..

사정거리 μ•ˆμ— μ—†μŒμ„ νŒλ‹¨ν•  수 μžˆλŠ” 쑰건은 두 κ°€μ§€λ‘œ μƒκ°ν–ˆλ‹€.

점 $\ a = (x_a,\space y_a)$ κ³Ό 사정거리 $\ L$ 에 λŒ€ν•˜μ—¬,

  1. λ§Œμ•½ 점의 $\ y_a > L$ 이면 사정거리 μ•ˆμ— μ—†λ‹€.
  2. $\ y_a \le L$일 λ•Œ, $\ x_a$λΆ€ν„° μ–‘μͺ½μœΌλ‘œ 각각 $\ (L-y_a)$ 만큼 떨어진 거리 내에 μ‚¬λŒ€κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, 사정거리 μ•ˆμ— μ—†λ‹€.

μœ„μ™€ 같은 κ·Έλ¦Όμ—μ„œ, 점 (4, 5)λŠ” yμ’Œν‘œ 5κ°€ 사정거리 L=4 보닀 크기 λ•Œλ¬Έμ— λ²—μ–΄λ‚˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

또 점 (8, 4)도 사정거리λ₯Ό λ²—μ–΄λ‚œλ‹€. μ΄λŠ” $\ x = 8 $ λ‘œλΆ€ν„° μ–‘μͺ½μœΌλ‘œ $\ (L-y) = (4, 4) = 0 $ 만큼 떨어진 곳에 μ‚¬λŒ€κ°€ μ—†κΈ° λ•Œλ¬Έμ΄λ‹€. 즉 μ’Œν‘œ 8에 μ‚¬λŒ€κ°€ μ—†μœΌλ―€λ‘œ, 사정거리λ₯Ό λ²—μ–΄λ‚  수 μžˆλ‹€. 두 번째 쑰건을 κ΅¬κ°„μœΌλ‘œ ν‘œν˜„ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

$\ (s, e) = (x-(L-y), \space x+(L-y)) $

μœ„ 그림을 보면, yμ’Œν‘œκ°€ L에 κ°€κΉŒμ›Œμ§ˆμˆ˜λ‘ μ‚¬μ •κ±°λ¦¬μ—μ„œ λ²—μ–΄λ‚˜κΈ° μœ„ν•œ xμ’Œν‘œμ™€ μ‚¬λŒ€μ™€μ˜ 거리가 4, 3, 2, 1둜 점차 μ€„μ–΄λ“œλŠ” 것을 λ³Ό 수 μžˆλ‹€.

λ”°λΌμ„œ, yμ’Œν‘œκ°€ Lμ΄ν•˜μΈ 각 점에 λŒ€ν•΄μ„œλŠ”, μ‚¬μ •κ±°λ¦¬μ—μ„œ λ²—μ–΄λ‚˜κΈ° μœ„ν•œ ꡬ간 (s, e)λ₯Ό κ³„μ‚°ν•˜κ³ , 이 ꡬ간 λ‚΄ μ‚¬λŒ€κ°€ μ‘΄μž¬ν•˜λŠ”μ§€λ§Œ μ²΄ν¬ν•˜λ©΄ λœλ‹€.

attackable() ν•¨μˆ˜μ˜ κ΅¬ν˜„

1. 첫 번째 방법: λ‹¨μˆœ 반볡 O(L)
def attackable(x, y):
  s, e = x-(L-y), x+(L-y)
    for i in range(s, e+1):
        if i in m:
            return True
    return False

점의 x, yμ’Œν‘œλ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ°›μ•„, ꡬ간 (s, e) λ‚΄ μ‚¬λŒ€μ˜ 쑴재 μ—¬λΆ€λ₯Ό μ²΄ν¬ν•˜μ—¬ λ°˜ν™˜ν•˜λŠ” attackable() ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•œλ‹€κ³  ν•˜μž. κ°€μž₯ κ°„λ‹¨ν•˜κ²ŒλŠ” μœ„μ™€ 같이 이 κ΅¬κ°„μ˜ λͺ¨λ“  μ–‘μ˜ μ •μˆ˜μ— λŒ€ν•΄ μ‚¬λŒ€μ˜ λ°°μ—΄ m에 μ‘΄μž¬ν•˜λŠ”μ§€λ₯Ό μ²΄ν¬ν•˜λŠ” λ‹¨μˆœ 반볡문이 μžˆμ„ 수 μžˆλ‹€. 이 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  경우, μ μˆ˜λŠ” 40점이 λ‚˜μ˜¨λ‹€.

μ΄μœ λŠ” ꡬ간 (s, e)의 길이가 L에 μ˜μ‘΄ν•˜λŠ”λ°, λ¬Έμ œμ—μ„œ 주어진 L의 λ²”μœ„κ°€ (1 <= L <= 1,000,000,000)이기 λ•Œλ¬Έμ΄λ‹€. μ΅œλŒ€ 2*L번 λ°˜λ³΅λ¬Έμ„ μˆ˜ν–‰ν•˜λ―€λ‘œ λ‹Ήμ—°νžˆ μ‹€ν–‰ μ‹œκ°„μ΄ κΈΈμ–΄μ Έ μ‹œκ°„ μ΄ˆκ³Όκ°€ λ°œμƒν•œλ‹€.

2. 두 번째 방법: 이쀑 포인터 O(M)
def attackable():
  s, e = x-(L-y), x+(L-y)
    # λ§Œμ•½ s == e 이면 이 xμ’Œν‘œμ— μ‚¬λŒ€κ°€ μžˆλŠ”μ§€λ§Œ 검사
    if s == e:
        return s in m
    i, j, k = 0, M-1, 0
    # two pointer둜 m[i] < s μ΄κ±°λ‚˜ m[i] > e 인 인덱슀 검색
    while k < M:
        if m[i] < s:
            i += 1
        if m[j] > e:
            j -= 1
        if i >= j:
            break
        k += 1
    if i > j:
        return False
    if i == j:
        if i == s or i == e:
            return False
        # λ§Œλ‚œ 값이 (s, e)에 μ†ν•˜λŠ”μ§€ λ°˜ν™˜
        return s <= m[i] <= e
    return True

κ·Έλž˜μ„œ L의 크기에 μ˜μ‘΄ν•˜μ§€ μ•ŠλŠ” λ°©μ‹μœΌλ‘œ ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•΄λ³΄μ•˜λ‹€. m배열이 μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬λ˜μ–΄ μžˆμœΌλ―€λ‘œ, μ–‘ λμ—μ„œλΆ€ν„° 이쀑 포인터λ₯Ό μ‚¬μš©ν•˜μ—¬ 쑴재 μ—¬λΆ€λ₯Ό 체크할 수 μžˆλ‹€. μ•žμ—μ„œλΆ€ν„° μ‹œμž‘ν•˜λŠ” 포인터 iλŠ” m[i] < s μΌλ•Œ 1 μ¦κ°€ν•˜λ©° 배열을 κ²€μ‚¬ν•œλ‹€. λ’€μ—μ„œλΆ€ν„° μ‹œμž‘ν•˜λŠ” 포인터 jλŠ” m[j] > e μΌλ•Œ 1 κ°μ†Œν•˜λ©° 배열을 κ²€μ‚¬ν•œλ‹€. λ§Œμ•½ i >= j 라면 λ°˜λ³΅λ¬Έμ„ νƒˆμΆœν•œλ‹€.

i == j 인 경우 이 인덱슀의 μ‚¬λŒ€κ°€ ꡬ간 (s, e)에 ν¬ν•¨λ˜λŠ”μ§€ ν•œλ²ˆ 더 κ²€μ‚¬ν•˜κ³  κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. i > j인 경우 ꡬ간이 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.

πŸ₯² ν•˜λ‚˜ν•˜λ‚˜ 값을 λ„£μ–΄κ°€λ©΄μ„œ λ””λ²„κΉ…ν•˜λ©° μ½”λ“œλ₯Ό 짰기에 μ½”λ“œκ°€ μ§€μ €λΆ„ν•˜λ‹€γ…œγ…œ 이 μ΄ν•˜λ‘œ μΌ€μ΄μŠ€λ₯Ό λ‚˜λˆ„μ–΄ κ²€μ‚¬ν•˜λŠ” 방식도 μžˆμ„ 것 κ°™λ‹€. μΆ”ν›„ κ°œμ„ ν•΄ λ³Ό 것. 이 μ½”λ“œλ₯Ό μ‚¬μš©ν•  경우 λ³΅μž‘λ„λŠ” O(M)이닀. μ΅œλŒ€ M번 λͺ¨λ“  μ‚¬λŒ€λ₯Ό 검사할 수 있기 λ•Œλ¬Έμ΄λ‹€. μ μˆ˜λŠ” 60점이 λ‚˜μ™”λ‹€.

3. μ„Έ 번째 방법: 이진 탐색 O(logM)
def attackable():
    s, e = x-(L-y), x+(L-y)
    # 검사할 ν•„μš”κ°€ μ—†λŠ” 경우
    if m[-1] < s or m[0] > e:
        return False

    # λ§Œμ•½ s = e이면 이 점이 μ‚¬λŒ€μΈμ§€λ§Œ 확인
    if s == e:
        return s in m

    v1, v2 = 0, M-1
    if m[0] >= s:
        # λ§Œμ•½ 첫번재 μ›μ†Œκ°€ s보닀 >=, λͺ¨λ“  μ›μ†Œκ°€ s보닀 >= (all T)
        v1 = 0
    else:
        # m[i] >= s 인 μ΅œμ†Œμ˜ κ°’ v1 탐색: lower bound
        # s보닀 ν¬κ±°λ‚˜ 같은 μˆ˜κ°€ 처음 λ“±μž₯ν•˜λŠ” μœ„μΉ˜λ₯Ό μ°ΎλŠ”λ‹€
        low, high = 0, M-1
        while low+1 < high:  # low와 high μ‚¬μ΄μ—λŠ” ν•œ μΉΈ 쑴재
            mid = (low+high)//2
            if m[mid] >= s:  # if true
                high = mid
            else:
                low = mid
        v1 = high

    if m[-1] <= e:
        # λ§Œμ•½ λ§ˆμ§€λ§‰ μ›μ†Œκ°€ e보닀 <=, λͺ¨λ“  μ›μ†Œκ°€ e보닀 <= (all F)
        v2 = M-1
    else:
        # m[i] > e 인 μ΅œμ†Œμ˜ κ°’ v2 탐색: upper bound
        # e보닀 큰 μˆ˜κ°€ 처음 λ“±μž₯ν•˜λŠ” μœ„μΉ˜λ₯Ό μ°ΎλŠ”λ‹€
        # 찾은 ν›„ high-1 ν•˜λ©΄ e보닀 μž‘κ±°λ‚˜ 같은 수의 μ΅œλŒ€ μΈλ±μŠ€κ°€ λœλ‹€
        low, high = 0, M-1
        while low+1 < high:
            mid = (low+high)//2
            if m[mid] > e:  # if true
                high = mid
            else:
                low = mid
        v2 = high-1

    # λ§Œμ•½ v1 > v2라면 λ²”μœ„λŠ” μ—†λ‹€
    if v1 > v2:
        return False
    return True

λ³΅μž‘λ„λ₯Ό logM으둜 쀄여 쀄 수 μžˆλŠ” 이진 탐색을 ν™œμš©ν•œ 방법이닀. 접근법은 이쀑 포인터와 μœ μ‚¬ν•˜λ‹€. λ¨Όμ € m[i] >= s 인 μ΅œμ†Œμ˜ iλ₯Ό μ°ΎλŠ”λ‹€. 그리고 m[j] <= e인 μ΅œλŒ€μ˜ jλ₯Ό μ°ΎλŠ”λ‹€. 그리고 i 와 j의 μœ„μΉ˜λ₯Ό λΉ„κ΅ν•˜μ—¬ κ΅¬κ°„μ˜ 쑴재 μ—¬λΆ€λ₯Ό μ²΄ν¬ν•œλ‹€.

이진/이뢄 탐색 Binary SearchλŠ” 배열을 λ‘˜λ‘œ λ‚˜λˆ„μ–΄ κ°€λ©΄μ„œ μ΅œμ κ°’μ„ μ°ΎκΈ° λ•Œλ¬Έμ— μœ„μ™€ 같은 μƒν™©μ—μ„œ 보닀 적은 μ‹œκ°„λ³΅μž‘λ„λ‘œ μ½”λ“œλ₯Ό 지 수 μžˆλ‹€. μ•„μ΄λ””μ–΄λŠ” 이해가 κ°”μ§€λ§Œ, low, mid, high의 값을 잘λͺ» μ„€μ •ν•˜λ©΄ μ˜€λ‹΅μ„ 뱉기 λ•Œλ¬Έμ— κ΅¬ν˜„μ—μ„œ ν—·κ°ˆλ¦¬λŠ” 뢀뢄이 λ§Žμ•˜λ‹€. (그리고 반볡문 νƒˆμΆœμ˜ 쑰건을 μ •ν™•νžˆ 넣어두지 μ•ŠμœΌλ©΄ λ¬΄ν•œλ£¨ν”„λ‘œ λŒμ•„κ°„λ‹€γ…œγ…œ)

κ·Έ λ•Œ 도움이 많이 λ˜μ—ˆλ˜ κΈ€ 둜 인해 μ–΄λŠ 정도 감을 μž‘μ€ 것 κ°™λ‹€. μ£Όμš” ν¬μΈνŠΈλŠ”

  1. 배열이 λͺ¨λ‘ True λ˜λŠ” λͺ¨λ‘ Falseκ°€ λ˜μ§€ μ•Šλ„λ‘ μ˜ˆμ™Έμ²˜λ¦¬ λ¨Όμ €
  2. T to F λ˜λŠ” F to T 배열에 λŒ€ν•΄ 값이 λ‹¬λΌμ§€λŠ” 경계λ₯Ό 검색
  3. λ§Œμ•½ check(low) != mid 이면 high = mid
  4. μ•„λ‹ˆλ©΄ low = mid
  5. λ§ˆμ§€λ§‰μ—λŠ” low λ°”λ‘œ λ‹€μŒμ΄ highκ°€ λœλ‹€.
  6. 이 λ•Œ κ΅¬ν•˜κ³ μž ν•˜λŠ” 닡이 low인지 high인지 μƒκ°ν•˜μ—¬ μ΅œμ’… 닡을 λ‚Έλ‹€

이 포인트λ₯Ό 가지고 attackable() ν•¨μˆ˜μ˜ 진행 과정을 λ‚˜νƒ€λ‚΄λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

# ꡬ간 (s, e)에 λ°°μ—΄ X의 값이 μ‘΄μž¬ν•˜λ©΄ True, μ•„λ‹ˆλ©΄ False

μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬λœ λ°°μ—΄ X와 s <= e인 ꡬ간 (s, e)에 λŒ€ν•΄,

1. s == e 이면:
  return s in X

2. X[i] >= s인 μ΅œμ†Œ i의 κ°’ v1 μ°ΎκΈ°
  a. if X[0] >= s 이면 λͺ¨λ‘ True인 배열이 λœλ‹€.
    λ”°λΌμ„œ v1 = 0
  b. if X[-1] < s 이면 λͺ¨λ‘ False인 배열이 λœλ‹€.
    검사할 ν•„μš” 없이, return False
  c. if False to True 이면
    경계λ₯Ό 이뢄 νƒμƒ‰ν•œλ‹€.
    while low+1 < high:
      mid = (low+high)//2
      if X[mid] >= s: # true 이면
        high = mid
      else:
        low = mid
    v1 = high # true인 값을 κ°€μ Έμ˜΄

3. X[j] <= e인 μ΅œλŒ€ j의 κ°’ v2 μ°ΎκΈ°
  λ¨Όμ € X[j] > e인 μ΅œμ†Œ jλ₯Ό μ°Ύκ³ , v2 = j-1
  a. if X[0] > e 이면 λͺ¨λ‘ True 인 배열이 λœλ‹€.
    검사할 ν•„μš” 없이, return False
  b. if X[-1] <= e 이면 λͺ¨λ‘ False 인 배열이 λœλ‹€.
    v2 = len(X)-1 λ§ˆμ§€λ§‰ μ›μ†Œ
  c. if False to True 이면
    while low+1 < high:
        mid = (low+high)//2
        if X[mid] > e:
          high = mid
        else:
          low = mid
    # highλŠ” e보닀 큰 μ΅œμ†Œ
    # λ”°λΌμ„œ high-1은 e보닀 μž‘κ±°λ‚˜ 같은 μ΅œλŒ€
    v2 = high - 1

4. if v1 > v2:
  λ²”μœ„κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ return False

5. else:
  λ²”μœ„μ— ν•΄λ‹Ήν•˜λŠ” ν•˜λ‚˜ μ΄μƒμ˜ μ›μ†Œκ°€ 있음
  return True

λ³΅μž‘ν•΄ λ³΄μ΄μ§€λ§Œ, μ˜ˆμ‹œλ₯Ό 듀어보면 κ°„λ‹¨ν•˜λ‹€.

X = [12, 14, 25, 37, 100, 105, 200]

+) lower/upper bounds?

μœ„μ— μ‚¬μš©ν•œ 것과 같이, μ •λ ¬λœ λ°°μ—΄μ—μ„œ νŠΉμ •κ°’ k 이상 λ˜λŠ” 초과인 μ΅œμ†Ÿκ°’μ„ μ°ΎλŠ” 것을 lower bound, upper bound ν•¨μˆ˜λΌκ³  λΆ€λ₯Έλ‹€. λ‚˜λŠ” e보닀 μž‘κ±°λ‚˜ 같은 μ΅œλŒ“κ°’μ„ μ°ΎκΈ° μœ„ν•΄ upper boundλ₯Ό 찾은 ν›„ -1 ν•΄μ£Όμ—ˆλ‹€.

  • lower bound: X[i] >= k인 μ΅œμ†Œμ˜ 인덱슀 i μ°ΎκΈ° (k이상인 값이 첫 번째둜 λ“±μž₯ν•˜λŠ” μœ„μΉ˜)
  • upper bound: X[i] > k인 μ΅œμ†Œμ˜ 인덱슀 i μ°ΎκΈ° (k보닀 큰 값이 첫 번째둜 λ“±μž₯ν•˜λŠ” μœ„μΉ˜)

이진 νƒμƒ‰μ—μ„œ μ‹€μˆ˜κ°€ 없도둝 문제λ₯Ό 꼼꼼히 읽고 κ°€λŠ₯ν•œ λͺ¨λ“  μΌ€μ΄μŠ€λ“€μ„ κ³ λ €ν•΄μ•Ό ν•œλ‹€.

μ–΄μ¨Œλ“ , μ΄λŒ€λ‘œ μ½”λ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 100점을 받을 수 μžˆλ‹€ !

03) μ½”λ“œ (파이썬)


def attackable(x, y):  # binary search
    s, e = x-(L-y), x+(L-y)
    # 검사할 ν•„μš”κ°€ μ—†λŠ” 경우
    if m[-1] < s or m[0] > e:
        return False

    # λ§Œμ•½ s = e이면 이 점이 μ‚¬λŒ€μΈμ§€λ§Œ 확인
    if s == e:
        return s in m

    v1, v2 = 0, M-1
    if m[0] >= s:
        # λ§Œμ•½ 첫번재 μ›μ†Œκ°€ s보닀 >=, λͺ¨λ“  μ›μ†Œκ°€ s보닀 >= (all T)
        v1 = 0
    else:
        # m[i] >= s 인 μ΅œμ†Œμ˜ κ°’ v1 탐색: lower bound
        # s보닀 ν¬κ±°λ‚˜ 같은 μˆ˜κ°€ 처음 λ“±μž₯ν•˜λŠ” μœ„μΉ˜λ₯Ό μ°ΎλŠ”λ‹€
        low, high = 0, M-1
        while low+1 < high: 
            mid = (low+high)//2
            if m[mid] >= s:  # if true
                high = mid
            else:
                low = mid
        v1 = high

    if m[-1] <= e:
        # λ§Œμ•½ λ§ˆμ§€λ§‰ μ›μ†Œκ°€ e보닀 <=, λͺ¨λ“  μ›μ†Œκ°€ e보닀 <= (all F)
        v2 = M-1
    else:
        # m[i] > e 인 μ΅œμ†Œμ˜ κ°’ v2 탐색: upper bound
        # e보닀 큰 μˆ˜κ°€ 처음 λ“±μž₯ν•˜λŠ” μœ„μΉ˜λ₯Ό μ°ΎλŠ”λ‹€
        # 찾은 ν›„ high-1 ν•˜λ©΄ e보닀 μž‘κ±°λ‚˜ 같은 수의 μ΅œλŒ€ μΈλ±μŠ€κ°€ λœλ‹€
        low, high = 0, M-1
        while low+1 < high:
            mid = (low+high)//2
            if m[mid] > e:  # if true
                high = mid
            else:
                low = mid
        v2 = high-1

    # λ§Œμ•½ v1 > v2라면 λ²”μœ„λŠ” μ—†λ‹€
    if v1 > v2:
        return False
    return True


M, N, L = map(int, input().split())
m = list(map(int, input().split()))
n = [list(map(int, sys.stdin.readline().split())) for _ in range(N)]


m.sort()
lower = m[0]-L
upper = m[-1]-L

excp = 0
# yμ’Œν‘œκ°€ L을 μ΄ˆκ³Όν•˜λ©΄ μ œμ™Έν•˜κ³ 
# λͺ¨λ“  점에 λŒ€ν•΄ 사정거리 μ•ˆμ— μžˆλŠ”μ§€ μ—¬λΆ€ 쑰사
for i in range(N):
    if n[i][1] > L:
        excp += 1
        continue
    if not attackable(n[i][0], n[i][1]):
        excp += 1

print(N-excp)

이진 탐색 문제λ₯Ό 처음 μ ‘ν–ˆμ„ λ•ŒλŠ” 무슨 말인지 ν•˜λ‚˜λ„ 이해 λͺ»ν•˜κ³  풀이λ₯Ό 봐도 λͺ¨λ₯΄κ² μ–΄μ„œ κ·Έμ € 울고만 μ‹Άμ—ˆλŠ”λ°, κ·Έλž˜λ„ ν•˜λ‚˜λ‘˜μ”© μ°Ύμ•„λ³΄λ©΄μ„œ μ–΄λŠ 정도 (μ•½ 1%) 감을 μž‘μ€ 것 κ°™λ‹€. 이 λ¬Έμ œλ„ λ‚˜λ¦„ κ³¨λ“œ4인데.. 이진 탐색 κ΅¬ν˜„μ„ 잘 λͺ» ν•΄μ„œ 방법을 검색해보긴 ν–ˆμ§€λ§Œ, λ‹΅μ•ˆ 없이 슀슀둜 μ ‘κ·Όλ²•κΉŒμ§€λŠ” 생각해낼 수 μžˆμ—ˆλ‹€λŠ” 것이 λΏŒλ“―ν•˜λ‹€ :) λ‹€μŒμ—λŠ” μ‹€μˆ˜ 없이 κ΅¬ν˜„κΉŒμ§€ λŠ₯μˆ™ν•˜κ²Œ λ§ˆλ¬΄λ¦¬ν•  수 μžˆλ„λ‘ 많이 μ—°μŠ΅ν•˜μžπŸ‘Š

Reference

이뢄 탐색(Binary Search) ν—·κ°ˆλ¦¬μ§€ μ•Šκ²Œ κ΅¬ν˜„ν•˜κΈ°
Theme 03. STL μ•Œκ³ λ¦¬μ¦˜ _ lower_bound, upper_bound