[BOJ] 7133 Milk and Honey

0. 들어가기

1. 문제 요약

  • 들판 NNN개가 있고, iii번째 들판은 소 CiC_iCi​마리 또는 벌 BiB_iBi​마리를 수용할 수 있다.
  • 모든 소는 우유를, 벌은 꿀을 하나씩 생산한다.
    • 한 들판에서, 첫 우유는 MMM의 가치를 가지고, 다음 우유는 M−DMM - D_MM−DM​, 그 다음 우유는 M−2∗DMM - 2 * D_MM−2∗DM​의 가치를 가진다.
    • 꿀도 마찬가지로 HHH, H−DHH - D_HH−DH​, H−2∗DHH - 2 * D_HH−2∗DH​ 처럼 가치가 하락한다.
    • 가치는 0보다 작아지지 않는다.
  • 들판 NNN개에서 생산한 우유와 꿀의 가치가 최대일 때, 해당 가치를 출력하라.

1.1. 입력

MMM DMD_MDM​
HHH DHD_HDH​
NNN
이후 NNN줄 동안 CCC BBB

  • MMM : 첫 우유의 가치, 0≤M≤10000 \le M \le 10000≤M≤1000
  • DMD_MDM​ : 감소하는 우유의 가치, 0≤DM≤M0 \le D_M \le M0≤DM​≤M
  • HHH : 첫 꿀의 가치, 0≤M≤10000 \le M \le 10000≤M≤1000
  • DHD_HDH​ : 감소하는 꿀의 가치, 0≤DH≤H0 \le D_H \le H0≤DH​≤H
  • NNN : 들판의 수, 1≤N≤10001 \le N \le 10001≤N≤1000
  • CCC : 어떤 들판이 수용할 수 있는 소의 수, 1≤C≤1001 \le C \le 1001≤C≤100
  • BBB : 어떤 들판이 수용할 수 있는 벌의 수, 1≤B≤1001 \le B \le 1001≤B≤100

2. 풀이 정리

  1. 어떤 들판에서 우유의 가치 MSUMM_{SUM}MSUM​
    • 해당 들판에서 키울 수 있는 소의 수는 CCC이다.
    • 소를 1마리 키운다면, 해당 들판에서 얻을 수 있는 우유의 총 가치는 MMM이다.
    • 소를 2마리 키운다면, 해당 들판에서 얻을 수 있는 우유의 총 가치는 M+(M−DM)M + (M - D_M)M+(M−DM​)이다.
    • 소를 3마리 키운다면, 해당 들판에서 얻을 수 있는 우유의 총 가치는 M+(M−DM)+(M−2∗DM)M + (M - D_M) + (M - 2 * D_M)M+(M−DM​)+(M−2∗DM​)이다.
    • 따라서 소를 CCC마리 키운다면, MSUMM_{SUM}MSUM​은 MMM부터 DMD_MDM​씩 줄여가면서 CCC번 더하면 된다.
      • for i in C: M_SUM += M; M -= D_M
      • 만약 중간에 M이 음수가 된다면, 반복을 멈추거나 M = 0처럼 처리해준다.
      • MSUMM_{SUM}MSUM​은 매 들판마다 구하지 않고, 미리 C=1000C = 1000C=1000까지 구해 M_SUM[1000]처럼 인덱싱 가능하도록 배열로 저장한다.
  2. 어떤 들판에서 꿀의 가치 HSUMH_{SUM}HSUM​
    • 1번과 마찬가지로 구해준다.
  3. 모든 들판 NNN개에 대해서, max(우유의 가치, 꿀의 가치)를 결과값에 더해주면 된다.
    • for i in N: ans += max(M_SUM[i], H_SUM[i])

3. 구현

#include <iostream> using namespace std; int M, D_M, H, D_H, N; int M_SUM[1005], H_SUM[1005]; int ans; int main() { cin >> M >> D_M; cin >> H >> D_H; cin >> N; M_SUM[1] = M; H_SUM[1] = H; for (int i = 2; i <= 1000; i++) { M = max(M - D_M, 0); M_SUM[i] = M_SUM[i - 1] + M; H = max(H - D_H, 0); H_SUM[i] = H_SUM[i - 1] + H; } while (N--) { int C, B; cin >> C >> B; ans += max(M_SUM[C], H_SUM[B]); } cout << ans; return 0; }