이 영역을 누르면 첫 페이지로 이동
포렌식 & 개발 이야기 - Forensics & Development 블로그의 첫 페이지로 이동

포렌식 & 개발 이야기 - Forensics & Development

페이지 맨 위로 올라가기

포렌식 & 개발 이야기 - Forensics & Development

Pental - Forensics / iOS / Windows / Android / Kakaotalk / Telegram / Etc

[골드 2] 백준 2878 - 캔디캔디 (파이썬)

  • 2025.06.25 20:40
  • Programming/백준
글 작성자: pental

https://www.acmicpc.net/problem/2878

풀이

총 M개의 캔디를 N명의 학생에게 나눠줘야 한다.

각 학생은 자신이 원하는 캔디 수가 있고, 그보다 적게 받으면 “화남 지수”가 받은 개수^2로 증가한다.

M개를 어떻게 배분해야 전체 화남 지수의 합이 최소가 되도록 하는지가 문제이다.

사용한 풀이 전략은 다음과 같다.

1. 이분 탐색을 이용해 평균 컷 구하기

  • 학생마다 min(A[i], mid) 만큼 주는 방식을 생각한다.
  • 이 때 mid를 조절하며, 총 줄 수 있는 캔디가 M 이상이 되는 최소 mid를 찾는다.
  • mid 이상을 주면 안 되고, 모든 학생에게 최대한 공평하게 적게 주자는 전략.

2. 이분 탐색 후 배분

  • 최적의 컷 수 p를 찾았으면,
  • 모든 학생에게 min(p - 1, A[i])만큼 먼저 배분한다.
  • 남은 캔디가 있다면, A[i] > 0인 학생에게 하나씩 더 나눠준다.

3. 화남 지수 계산

  • 학생별로 받은 캔디 수의 제곱을 합해 최종 정답을 구한다.
M, N = map(int, input().split())
A = [int(input()) for _ in range(N)]

M은 전체 캔디 수, N은 학생 수, A는 각 학생이 원하는 캔디 수이다.

debt = max(0, sum(A) - M)
low, high, p = 0, max(A), -1

while low <= high:
    mid = (low + high) // 2
    pay_back = sum(min(mid, x) for x in A)

    if debt <= pay_back:
        p = mid
        high = mid - 1
    else:
        low = mid + 1

pay_back은 각 학생이 mid 이상 못 받게 했을 때 줄 수 있는 총량이다.

debt는 총 원하는 양 - M, 즉 못 주는 양이다.

p를 찾는 이유는 학생들이 p이상 받으면 안되게끔 제한하기 위해서 사용된다.

캔디를 배분한다.

angry = [0] * N
for i in range(N):
    if A[i] >= p - 1:
        debt -= p - 1
        angry[i] += p - 1
        A[i] -= p - 1
    else:
        debt -= A[i]
        angry[i] += A[i]
        A[i] = 0

각 학생에게 먼저 p - 1 또는 가능한 만큼 배분한다.

if debt:
    for i in range(N):
        if debt > 0 and A[i] > 0:
            debt -= 1
            angry[i] += 1
            A[i] -= 1

그리고 남은 캔디가 있으면 하나씩 더 준다.

그리고 화남 지수를 계산해준다.

answer = 0
for i in range(N):
    answer += (angry[i] ** 2) % mod

print(answer)

각 학생의 화남 지수는 (받은 캔디 수) ** 2이고, 이를 모두 더해서 출력한다.

결론적으로, 이 문제는 단순히 그리디하게 큰 학생부터 나눠주는 것이 아닌, 캔디 개수의 상한선을 이분 탐색으로 찾고, 그 기준으로 나눠주는 공평한 분배 전략이 필요하다.

코드

# 백준 2878 - 캔디캔디
# 분류 : 이분 탐색

M, N = map(int, input().split())
A = [int(input()) for _ in range(N)]

mod = 2 ** 64

debt = max(0, sum(A) - M)

low, high, p = 0, max(A), -1

while low <= high :
    mid = (low + high) // 2

    pay_back = 0
    for i in range(N) :
        if A[i] >= mid :
            pay_back += mid
        else :
            pay_back += A[i]

    if debt <= pay_back :
        p = mid
        high = mid - 1
    else :
        low = mid + 1

# p, p - 1, A[i]

angry = [0] * N
for i in range(N) :
    if A[i] >= p - 1 :
        debt -= p - 1
        angry[i] += p - 1
        A[i] -= p - 1
    else :
        debt -= A[i]
        angry[i] += A[i]
        A[i] = 0

if debt :
    for i in range(N) :
        if debt > 0 and A[i] > 0 :
            debt -= 1
            angry[i] += 1
            A[i] -= 1

answer = 0
for i in range(N) :
    answer += (angry[i] ** 2) % mod

print(answer)

 

저작자표시 비영리 (새창열림)

'Programming > 백준' 카테고리의 다른 글

[실버 2] 백준 13423 - Three Dots  (0) 2025.06.25
[실버 5] 백준 12871 - 무한 문자열 (파이썬)  (0) 2025.06.25
[실버 1] 백준 1141 - 접두사 (파이썬)  (1) 2025.06.24
[골드 4] 백준 16120 - PPAP (파이썬)  (0) 2025.06.23
[골드 3] 백준 1670 - 정상 회담 2 (파이썬)  (0) 2025.06.22

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [실버 2] 백준 13423 - Three Dots

    [실버 2] 백준 13423 - Three Dots

    2025.06.25
  • [실버 5] 백준 12871 - 무한 문자열 (파이썬)

    [실버 5] 백준 12871 - 무한 문자열 (파이썬)

    2025.06.25
  • [실버 1] 백준 1141 - 접두사 (파이썬)

    [실버 1] 백준 1141 - 접두사 (파이썬)

    2025.06.24
  • [골드 4] 백준 16120 - PPAP (파이썬)

    [골드 4] 백준 16120 - PPAP (파이썬)

    2025.06.23
다른 글 더 둘러보기

정보

포렌식 & 개발 이야기 - Forensics & Development 블로그의 첫 페이지로 이동

포렌식 & 개발 이야기 - Forensics & Development

  • 포렌식 & 개발 이야기 - Forensics & Development의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

카테고리

  • Category (460) N
    • Forensics (105)
      • Magnet AXIOM (28)
      • Digital Forensics Informati.. (9)
      • Iphone Forensics (24)
      • DFC (7)
      • 디지털포렌식전문가2급 자격증 (10)
      • FTK ACE 자격증 (7)
    • 이것저것 (7)
      • Ubuntu (6)
      • 디스코드 봇 (4)
      • Volatility GUI (2)
    • CTF (32)
      • NEWSECU (14)
      • CTF-d (5)
      • Puzzel - Network Forensics (2)
      • Security Traps (2)
      • system32.kr (5)
      • HMCTF (4)
    • Programming (268) N
      • C (10)
      • Python (11)
      • 백준 (214) N
      • 프로그래머스 (32)
    • 그냥 개발 및 잡담 (16)
      • Docker (2)
      • Google Cloud (3)
      • OS 개발 (3)
    • Best of Best (20)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • 파이썬
  • 프로그래머스
  • 디지털포렌식
  • Forensics
  • pental
  • 백준
  • axiom
  • 포렌식
  • 전체 보기…

정보

pental의 포렌식 & 개발 이야기 - Forensics & Development

포렌식 & 개발 이야기 - Forensics & Development

pental

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © pental.

티스토리툴바