728x90
시간 제한 2초, 메모리 제한 128MB
# 조건
- 고객이 두 종류의 피자 A와 B를 취급하는 피자가게에서 피자를 주문하고자 한다.
- <그림 1>과 같이 각 종류의 피자는 다양한 크기의 여러 개의 피자조각으로 나누어져 있다.
- 각 조각에 쓰여진 숫자는 피자조각의 크기를 나타낸다.
- 고객이 원하는 피자의 크기를 이야기하면, 피자가게에서는 한 종류의 피자를 2 조각 이상 판매할 때는 반드시 연속된 조각들을 잘라서 판매한다.
- 이때 판매한 피자조각의 크기 합이 주문한 크기가 되어야 한다.
- 판매한 피자조각은 모두 A종류이거나, 모두 B종류이거나, 또는 A와 B 종류가 혼합될 수 있다.
- 예를 들어서, <그림 1> 과 같이 잘라진 피자가 있을 때, 손님이 전체 크기가 7 인 피자를 주문하면, 피자 가게에서는 <그림2>와 같이 5 가지 방법으로 피자를 판매할 수 있다.
- 피자가게에서 손님이 원하는 크기의 피자를 판매하는 모든 방법의 가지 수를 계산하는 프로그램을 작성하시오
입력
- 첫 번째 줄에는 손님이 구매하고자 하는 피자크기를 나타내는 2,000,000 이하의 자연수가 주어진다.
- 두 번째 줄에는 A, B 피자의 피자조각의 개수를 나타내 는 정수 m, n 이 차례로 주어진다 (3 ≤ m, n ≤ 1000).
- 세 번째 줄부터 차례로 m 개의 줄에는 피자 A의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다.
- 그 다음 n 개의 줄에는 차례로 피자B의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다.
- 각 종류의 피자조각의 크기는 시계방향으로 차례로 주어지며, 각 피자 조각의 크기는 1000 이하의 자연수이다.
출력
- 첫째 줄에는 피자를 판매하는 방법의 가지 수를 나타내는 정수를 출력한다.
- 피자를 판매하는 방법이 없는 경우에는 숫자 0을 출력한다.
# 접근 방법
- 한 종류의 피자에서 2조각 이상을 판매할 때는 반드시 연속된 조각들을 잘라서 판매해야 되는 것이기에 누적합을 떠올렸다.
- 이 때, 하나의 조각에서 나올 수 있는 모든 경우의 수를 저장해주어야 한다.
- 1 2 3 4 5 의 조각이 있다면 원형으로 되어있기에 1 2 3 5 도 연속된 조각으로 판단할 수 있기 때문이다.
- prefix 배열을 A와 B에 대해 만들어주는데 N을 넘어가면 안되기에 크기는 N+1로 만들어 준다.
- 반복문 2개를 이용하여 모든 경우의 수를 구해주며 예제의 경우
- 2 2 1 7 2, 2 1 7 2 2, 1 7 2 2 2 와 같이 제일 앞을 돌려주며 경우의 수를 구해주고
- N의 크기를 넘어선다면 종료, 아니라면 만들어준 prefix 리스트에 경우의 수를 더해준다.
- 출력은
- A에서 나올 수 있는 N의 개수 + B에서 나올 수 있는 N의 개수 + prefix_A[i] * B에서 [N - i] 곱 을 해주면 된다.
- 7의 경우 A에서 2, B에서 5를 만드는 것과 같이 N을 만들 수 있고 경우의 수이므로 곱하기로 더해준다.
- A에서 나올 수 있는 N의 개수 + B에서 나올 수 있는 N의 개수 + prefix_A[i] * B에서 [N - i] 곱 을 해주면 된다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
def prefix(arr, leng, kind):
# 각 피자에 대한 전체 경우의 수 구해주기
for i in range(leng):
val = 0
# 범위의 경우 피자는 원형이므로 제일 앞과 제일 뒤의 조각도 연결되어있다
# 따라서 2 2 1 7 2 -> 2 1 7 2 2 와 같이 돌려가며 구해준다. # 따라서 마지막에 피자 전체크기를 1로 초기화해주는 작업 필요
for now in arr[i:] + arr[:i]:
val += now
# 구해야되는 크기 넘어가면 종료
if val > N:
break
if kind == 0:
prefix_A[val] += 1
else:
prefix_B[val] += 1
# 피자 전체 크기는 1번만 나오도록 해주어야 한다.
if sum(A) <= N:
prefix_A[sum(A)] = 1
if sum(B) <= N:
prefix_B[sum(B)] = 1
N = int(input())
a, b = map(int, input().split())
A, B = [int(input()) for _ in range(a)], [int(input()) for _ in range(b)]
prefix_A, prefix_B = [0] * (N+1), [0] * (N+1)
prefix(A, len(A), 0)
prefix(B, len(B), 1)
# 출력은 A와 B에서 각각 독립적으로 N을 만드는 경우의 수를 더해주고
# 7의 경우 A에서 크기 3, B에서 크기 4를 만드는 경우의 수를 곱해주어야 한다.
print(prefix_A[N] + prefix_B[N] + sum([prefix_A[i] * prefix_B[N-i] for i in range(N)]))
728x90
'ALGORITHM > 정렬, 탐색,구현' 카테고리의 다른 글
[백준 2188번] 파이썬 - 축사 배정 (0) | 2023.08.09 |
---|---|
[백준 1348번] 파이썬 - 주차장 (0) | 2023.08.09 |
[백준 16916번] 파이썬 - 부분 문자열 (0) | 2023.08.07 |
[백준 25907번] 파이썬 - 양과 늑대 (0) | 2023.08.04 |
[프로그래머스 Lv3] 파이썬 - 파괴되지 않은 건물 (0) | 2023.08.03 |