Skip to content

Conversation

@Seol-Munhyeok
Copy link
Collaborator

@Seol-Munhyeok Seol-Munhyeok commented Sep 3, 2025

πŸ”— 문제 링크

μ±… νŽ˜μ΄μ§€
https://www.acmicpc.net/problem/1019

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

1μ‹œκ°„

✨ μˆ˜λ„ μ½”λ“œ

주의 : 이 λ¬Έμ œλŠ” 풀이λ₯Ό 봐도 μ–΄λ €μš°λ‹ˆ λ„μ €νžˆ μ•ˆ 풀리면 λ°”λ‘œ 풀이λ₯Ό λ³΄λŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€.

문제 μžμ²΄λŠ” μ΄ˆλ“±ν•™μƒλ„ 이해할 μ •λ„λ‘œ μ‰½μ§€λ§Œ μƒλ‹Ήνžˆ μ–΄λ €μš΄ λ¬Έμ œμž…λ‹ˆλ‹€. 일단 μž…λ ₯이 $N=10^9$ μ΄λ―€λ‘œ $O(N)$으둜 탐색해도 μ‹œκ°„μ΄ˆκ³Όκ°€ λ°œμƒν•©λ‹ˆλ‹€. 이 문제λ₯Ό ν’€κΈ° μœ„ν•΄μ„œλŠ” λ­”κ°€ μˆ˜ν•™μ μΈ λ°œμƒμ΄ ν•˜λ‚˜ ν•„μš”ν•©λ‹ˆλ‹€.

ν’€μ΄λŠ” λ°±μ€€ 온라인 μ €μ§€λ₯Ό λ§Œλ“œμ‹  μ΅œλ°±μ€€ λ‹˜κ»˜μ„œ 올린 μŠ¬λΌμ΄λ“œλ₯Ό μ°Έκ³ ν–ˆμŠ΅λ‹ˆλ‹€.
https://www.slideshare.net/slideshow/baekjoon-online-judge-1019/52810015

μ•„μ΄λ””μ–΄λŠ” AλΆ€ν„° BκΉŒμ§€ 각 μˆ«μžκ°€ λͺ‡ 번 λ‚˜μ˜€λŠ”μ§€λ₯Ό μ°ΎλŠ” 문제둜 λ°”κΏ”μ„œ μƒκ°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
μ΄λ•Œ A의 μΌμ˜μžλ¦¬κ°€ 0이고, B의 μΌμ˜μžλ¦¬κ°€ 9인 경우, A와 Bμ‚¬μ΄μ˜ 수의 0-9κ°€ 일의 μžλ¦¬μ— 각각 λͺ‡ λ²ˆμ”© λ‚˜μ˜€λŠ”μ§€λ₯Ό λ°”λ‘œ 계산할 수 μžˆμŠ΅λ‹ˆλ‹€.

image

예λ₯Ό λ“€μ–΄ A=10, B=39인 경우, 일의 μžλ¦¬μ—λŠ” 0-9κ°€ 총 3λ²ˆμ”© λ‚˜μ˜€λŠ” κ±Έ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

image

μžλ¦¬μˆ˜κ°€ λŠ˜μ–΄μ„œ A=110, B=130인 κ²½μš°λ„, 일의 μžλ¦¬μ—μ„œλŠ” 0-9κ°€ 13-11+1=3λ²ˆμ”© λ‚˜μ˜€λŠ” κ±Έ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ μš°λ¦¬λŠ” A의 끝 자리λ₯Ό 0, B의 끝자리λ₯Ό 9둜 맞좘 λ²”μœ„μ•ˆμ—μ„œλŠ” A와 B사이에 0-9κ°€ 총 λͺ‡ 번 λ‚˜μ˜€λŠ”μ§€λ₯Ό λ°”λ‘œ 계산할 수 μžˆμŠ΅λ‹ˆλ‹€. A의 끝 자리λ₯Ό 0, B의 끝자리λ₯Ό 9둜 맞좜 λ•ŒκΉŒμ§€ AλŠ” +1, BλŠ” -1ν•˜λ©΄μ„œ κ·Έ λ•Œμ˜ A, BλŠ” λ”°λ‘œ μˆ«μžκ°€ λ‚˜μ˜€λŠ” 횟수λ₯Ό κ³„μ‚°ν•˜λ©΄ λ©λ‹ˆλ‹€.

μ½”λ“œλ‘œ κ΅¬ν˜„ν•  λ•ŒλŠ” A % 10 을 ν•˜λ©΄ 수의 일의 μžλ¦¬μˆ˜κ°€ λ‚˜μ˜€κ³ , A // 10을 ν•˜λ©΄ 일의 자리 수λ₯Ό λ—€ μˆ«μžκ°€ λ‚˜μ˜¨λ‹€λŠ” 점을 μ‚¬μš©ν•©λ‹ˆλ‹€.

image

μ΄λ•Œ μ£Όμ˜ν•  점은 μ‹­μ˜ μžλ¦¬μ— μœ„μΉ˜ν•œ 0-9의 개수λ₯Ό ꡬ할 λ•ŒλŠ” μ›λž˜ κ³΅μ‹μ—μ„œ *10을 ν•΄μ£Όμ–΄μ•Όν•©λ‹ˆλ‹€.
μœ„ 그림처럼 μš°λ¦¬κ°€ 11이라고 λ³΄λŠ” κ±°λŠ” 사싀 뒀에 0-9κ°€ 뢙은 110, 111, 112, 113, 114, ... κ°€ ν•œ λ©μ–΄λ¦¬λ‘œ λ˜μ–΄μžˆλ‹€κ³  λ³΄λŠ” κ²λ‹ˆλ‹€.
λ§ˆμ°¬κ°€μ§€λ‘œ 백의 μžλ¦¬μ— μœ„μΉ˜ν•œ 0-9의 개수λ₯Ό ꡬ할 λ•ŒλŠ” μ›λž˜ κ³΅μ‹μ—μ„œ *100을 ν•΄μ£Όλ©΄ λ©λ‹ˆλ‹€.

μ†ŒμŠ€ μ½”λ“œ

answer = [0] * 10  # 0~9 각 숫자의 총 λ“±μž₯ 횟수λ₯Ό 담을 λ°°μ—΄

start = 1  # μ™Όμͺ½ 포인터: 아직 μ„Έμ§€ μ•Šμ€ μ΅œμ†Œ 숫자
end = int(input())    # 였λ₯Έμͺ½ 포인터: 아직 μ„Έμ§€ μ•Šμ€ μ΅œλŒ€ 숫자(μž…λ ₯ N)
ten = 1  # ν˜„μž¬ λ°”λΌλ³΄λŠ” μžλ¦Ώκ°’(일=1, μ‹­=10, λ°±=100, ...)

# 숫자 n이 μ§€κΈˆ λ°”λΌλ³΄λŠ” μžλ¦Ώκ°’(ten=1,10,100,...)μ—μ„œ
# '접두사'λ‘œμ„œ κΈ°μ—¬ν•˜λŠ” κ³ μ • λ“±μž₯ 횟수λ₯Ό answer에 λ”ν•œλ‹€.
# 예λ₯Όλ“€μ–΄ calc(12345, 1)은 answer[5], answer[4], ... answer[1]에 +1
# +ten을 ν•˜λŠ” μ΄μœ λŠ” ν˜„μž¬ 자리 μ•„λž˜μͺ½μ—λŠ” 항상 tenκ°€μ§€(0..ten-1)의 쑰합이 κΉ”λ¦¬λ―€λ‘œ,
# κ·Έ 자리의 같은 숫자 dκ°€ 블둝 μ•ˆμ—μ„œ μ •ν™•νžˆ ten번 λ“±μž₯ν•˜κΈ° λ•Œλ¬Έ.
def calc(n, ten):
    while n > 0:
        answer[n % 10] += ten
        n //= 10

# λ°”κΉ₯ while ν•œ 바퀴 = μžλ¦Ώκ°’ 'ten' ν•˜λ‚˜λ₯Ό μ™„μ „νžˆ 처리
while start <= end:
    # [1] μ™Όμͺ½ λͺ¨μ„œλ¦¬ 정리: startλ₯Ό '...0'으둜 맞좜 λ•ŒκΉŒμ§€ κ°œλ³„ 처리
    while start % 10 != 0 and start <= end:
        calc(start, ten)
        start += 1
    if start > end: break  # λ‹€ λλ‚˜λ©΄ μ’…λ£Œ

    # [2] 였λ₯Έμͺ½ λͺ¨μ„œλ¦¬ 정리: endλ₯Ό '...9'둜 맞좜 λ•ŒκΉŒμ§€ κ°œλ³„ 처리
    while end % 10 != 9 and start <= end:
        calc(end, ten)
        end -= 1

    # μ—¬κΈ°κΉŒμ§€ 였면 [start, end]λŠ” ν˜„μž¬ μžλ¦¬μ—μ„œ
    # μ •ν™•νžˆ '...0 ~ ...9'κ°€ λ°˜λ³΅λ˜λŠ” 'μ™„μ „ μ£ΌκΈ° ꡬ간'이 됨.

    # [3] κ°€μš΄λ° μ™„μ „ μ£ΌκΈ° ν•œ λ²ˆμ— λ”ν•˜κΈ°
    # cnt = ν˜„μž¬ μžλ¦¬μ—μ„œ μ„œλ‘œ λ‹€λ₯Έ '접두사' 개수
    # (접두사 ν•˜λ‚˜λ§ˆλ‹€ 0~9 각 μˆ«μžκ°€ ν•˜μœ„ ten가지와 κ²°ν•©ν•˜λ―€λ‘œ
    # 각 μˆ«μžκ°€ μ •ν™•νžˆ 'ten'λ²ˆμ”© λ“±μž₯)
    cnt = (end // 10) - (start) // 10 + 1
    for d in range(0, 10):
        answer[d] += cnt * ten

    # [4] ν•œ 자리 올림: ν˜„μž¬ 자리 처리λ₯Ό λλƒˆμœΌλ‹ˆ μœ—μžλ¦¬λ‘œ 이동
    start //= 10
    end //= 10
    ten *= 10

# κ²°κ³Ό 좜λ ₯
for d in range(0, 10):
    print(answer[d], end=' ')

μ € μ—­μ‹œ 이해가 μ‰½μ§€μ•Šμ•„μ„œ 주석을 정말 μžμ„Ένžˆ μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€.
주석 쀑 '접두사'λΌλŠ” μ˜λ―ΈλŠ” μ•žμ—μ„œ μ„€λͺ…ν•œ μ‹­μ˜ μžλ¦¬μ— μœ„μΉ˜ν•œ 0-9의 개수λ₯Ό ꡬ할 λ•ŒλŠ” μ›λž˜ κ³΅μ‹μ—μ„œ *10, 백의 μžλ¦¬λŠ” *100 을 ν•΄μ•Όν•œλ‹€λŠ” 것과 같은 μ˜λ―Έμž…λ‹ˆλ‹€.

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

사싀 N=9, 99, 999, 9999 같은 수일 λ•ŒλŠ” λ‹€μŒκ³Ό 같은 κ·œμΉ™μ΄ μžˆμŠ΅λ‹ˆλ‹€.
image

μ΄λŸ¬ν•œ κ·œμΉ™μ„ μ΄μš©ν•΄μ„œ λ‚΄κ°€ μ°ΎλŠ” 수λ₯Ό 000...0 λΆ€ν„° x999..9 κΉŒμ§€μ˜ λ²”μœ„λ‘œ μ’νžˆλŠ” 방법을 λ°˜λ³΅ν•΄μ„œ ν‘ΈλŠ” 풀이도 μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜ 링크λ₯Ό μ°Έκ³ ν•˜μ„Έμš”!
https://dorianyellow.tistory.com/120

@hyeokbini
Copy link
Collaborator

hyeokbini commented Sep 8, 2025

λ­”κ°€ 될 것 같은데 μ•ˆ λΌμ„œ μ•„μ‰½λ„€μš”. 1μ‹œκ°„μ •λ„ κ³ λ―Όν•΄λ΄€λŠ”λ° κ²°κ΅­ 둜직 정리 μžμ²΄λΆ€ν„° μ‹€νŒ¨ν•˜κ³  풀이λ₯Ό μ°Ύμ•„λ΄€μŠ΅λ‹ˆλ‹€. 풀이λ₯Ό λ³΄λ‹ˆ μ‹€νŒ¨ν–ˆλ˜ 게 납득이 λ˜κΈ°λ„ ν•˜λ„€μš”...

μ°Έκ³  풀이 링크

λ¬Έν˜λ‹˜μ΄ 가져와주신 ν’€μ΄λŠ” 기쀀점을 직접 λŠ˜λ €μ„œ xx..0 ~ xx..9둜 맞좘 λ‹€μŒ μΉ΄μš΄νŒ…μ„ ν•˜λŠ” 방식이라면, 이뢄 ν’€μ΄λŠ” μ•„μ˜ˆ 0λΆ€ν„° μ‹œμž‘ν•˜κ³  9μ—μ„œ λλ‚˜λ„λ‘ λ°˜λ³΅λ¬Έμ„ κ΅¬μ„±ν•˜λ˜, ν˜„μž¬ 자릿수의 숫자 μ™Όμͺ½ / 였λ₯Έμͺ½μ„ λ”°λ‘œ μΉ΄μš΄νŒ…ν•˜λŠ” 방식인 것 κ°™μŠ΅λ‹ˆλ‹€. 두 풀이 λͺ¨λ‘ κ²°κ΅­ 기쀀점 λ‹¨μœ„λ‘œ ν•œ 열을 μ‚΄νŽ΄λ³Έλ‹€ λΌλŠ” μ•„μ΄λ””μ–΄λŠ” λΉ„μŠ·ν•œ 것 κ°™μ•„μš”.

μ–Έμ  κ°€ λ‹€μ‹œ 풀어보고 싢기도 ν•˜κ³ , λ‹΅λ§Œ 보고 μ΄ν•΄ν•œ 문제인 것 κ°™μ•„μ„œ μ½”λ“œ μ œμΆœμ€ ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. ν‘Έμ‹œλŠλΌ κ³ μƒν•˜μ…¨μ–΄μš”! πŸ˜„

@Seol-Munhyeok
Copy link
Collaborator Author

Seol-Munhyeok commented Sep 8, 2025

λ‹€λ₯Έ 풀이가 μžˆμ–΄μ„œ μΆ”κ°€ν•©λ‹ˆλ‹€.
이 문제λ₯Ό λ‹¨μˆœν•œ λ°©λ²•μœΌλ‘œ ν’€λ©΄ λŒ€λž΅ μ‹œκ°„ λ³΅μž‘λ„κ°€ $O(N)$ 인데 이 경우 $10^8$κΉŒμ§€λŠ” κΉ‘ κ΅¬ν˜„μœΌλ‘œ ν’€λ¦½λ‹ˆλ‹€.
λ˜ν•œ 1e8, 2e8, … 1e9 같은 νŠΉμ§•μ μΈ μˆ˜μ— λŒ€ν•΄μ„œλŠ” κ·œμΉ™μ„±μ΄ μžˆμœΌλ―€λ‘œ, 이 κ²½μš°λŠ” μ „λΆ€ ν•˜λ“œμ½”λ”©μœΌλ‘œ μž‘μ„±ν•˜μ—¬ 미리 κ°’(cnt)을 λ„£μ–΄ 두고, κ·Έ λ’€ 꼬리 κ΅¬κ°„λ§Œ λ§ˆμ € μ„ΈλŠ” λ°©μ‹μœΌλ‘œλ„ ν’€ 수 μžˆμŠ΅λ‹ˆλ‹€.

def solve(n: int):
    x = 1
    s = 1
    cnt = [0] * 10

    if n == 1_000_000_000:
        x = 10
        s = 1_000_000_001
        cnt = [788888898, 900000001, 900000000, 900000000, 900000000,
               900000000, 900000000, 900000000, 900000000, 900000000]
    elif n >= 900_000_000:
        x = 9
        s = 900_000_001
        cnt = [708888897, 820000000, 820000000, 820000000, 820000000,
               820000000, 820000000, 820000000, 820000000, 720000001]
    elif n >= 800_000_000:
        x = 9
        s = 800_000_001
        cnt = [628888897, 740000000, 740000000, 740000000, 740000000,
               740000000, 740000000, 740000000, 640000001, 640000000]
    elif n >= 700_000_000:
        x = 9
        s = 700_000_001
        cnt = [548888897, 660000000, 660000000, 660000000, 660000000,
               660000000, 660000000, 560000001, 560000000, 560000000]
    elif n >= 600_000_000:
        x = 9
        s = 600_000_001
        cnt = [468888897, 580000000, 580000000, 580000000, 580000000,
               580000000, 480000001, 480000000, 480000000, 480000000]
    elif n >= 500_000_000:
        x = 9
        s = 500_000_001
        cnt = [388888897, 500000000, 500000000, 500000000, 500000000,
               400000001, 400000000, 400000000, 400000000, 400000000]
    elif n >= 400_000_000:
        x = 9
        s = 400_000_001
        cnt = [308888897, 420000000, 420000000, 420000000, 320000001,
               320000000, 320000000, 320000000, 320000000, 320000000]
    elif n >= 300_000_000:
        x = 9
        s = 300_000_001
        cnt = [228888897, 340000000, 340000000, 240000001, 240000000,
               240000000, 240000000, 240000000, 240000000, 240000000]
    elif n >= 200_000_000:
        x = 9
        s = 200_000_001
        cnt = [148888897, 260000000, 160000001, 160000000, 160000000,
               160000000, 160000000, 160000000, 160000000, 160000000]
    elif n >= 100_000_000:
        x = 9
        s = 100_000_001
        cnt = [68888897, 80000001, 80000000, 80000000, 80000000,
               80000000, 80000000, 80000000, 80000000, 80000000]

    for i in range(s, n + 1):
        if i in (10, 100, 1000, 10000, 100000,
                 1000000, 10000000, 100000000, 1000000000):
            x += 1
        b = i
        for _ in range(x):
            cnt[b % 10] += 1
            b //= 10

    return cnt


# μ‹€ν–‰ μ˜ˆμ‹œ
n = int(input().strip())
result = solve(n)
print(*result)
image

무렀 4μ΄ˆλ‚˜ κ±Έλ¦¬μ§€λ§Œ... μ•„λ¬΄νŠΌ 풀리긴 ν’€λ¦½λ‹ˆλ‹€. 이런 방식을 λŸ°νƒ€μž„ μ „μ˜ μ „μ²˜λ¦¬λΌκ³  ν•œλ‹€κ³  ν•©λ‹ˆλ‹€.
미리 ν•˜λ“œμ½”λ”©μœΌλ‘œ μ²˜λ¦¬ν•  수 μžˆλŠ” 뢀뢄은 μ²˜λ¦¬ν•˜κ³ , λ‚˜λ¨Έμ§€ λΆ€λΆ„λ§Œ κ³„μ‚°ν•œλ‹€λŠ” 아이디어λ₯Ό μ–»μ–΄κ°€μ‹œλ©΄ 쒋을 κ±° κ°™μŠ΅λ‹ˆλ‹€.

Copy link
Collaborator

@flydongwoo flydongwoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ„ˆλ¬΄ μ–΄λ ΅λ„€μš” γ…œγ…œ μ§€μ„ μƒλ‹˜ 도움 λ°›μ•„ μ–‘ 끝을 μ‘°μ •ν•΄ μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜κ³ , κ°€μš΄λ° ꡬ간은 자리수 반볡 νŒ¨ν„΄μ„ μ΄μš©ν•΄ ν•œ λ²ˆμ— μΉ΄μš΄νŠΈν•˜λŠ” λ°©μ‹μœΌλ‘œ 문제λ₯Ό ν’€μ—ˆμŠ΅λ‹ˆλ‹€.

μ±… νŽ˜μ΄μ§€
#include <iostream>
#include <vector>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    long long N;
    cin >> N;

    vector<long long> cnt(10, 0);

    long long a = 1;
    long long b = N;
    long long digit = 1;

    while (a <= b) {
        while (a % 10 != 0 && a <= b) {
            long long x = a;
            for ( ; x > 0; x /= 10) {
                cnt[x % 10] += digit;
            }
            a++;
        }
        if (a > b) {
            break;
        }
        while (b % 10 != 9 && a <= b) {
            long long x = b;
            for ( ; x > 0; x /= 10) {
                cnt[x % 10] += digit;
            }
            b--;
        }
        long long groups = (b / 10 - a / 10 + 1);
        for (int d = 0; d < 10; d++) {
            cnt[d] += groups * digit;
        }
        a /= 10;
        b /= 10;
        digit *= 10;
    }

    for (int d = 0; d < 10; d++) {
        cout << cnt[d];
        if (d < 9) {
            cout << ' ';
        }
    }
    cout << endl;

    return 0;
}

문제 ν‘ΈλŠλΌ 고생 λ§ŽμœΌμ…¨μŠ΅λ‹ˆλ‹€~!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants