https://www.acmicpc.net/problem/21758
#include <iostream>
#include <vector>
using namespace std;
vector<int> honey;
vector<int> prefix;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
int ans = 0;
cin >> n;
honey.resize(n);
prefix.resize(n);
for (int i = 0; i < n; i++) {
cin >> honey[i];
if (i == 0) {
prefix[i] = honey[i];
} else {
prefix[i] = prefix[i - 1] + honey[i];
}
}
//벌 꿀통 벌->꿀통의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[i] - prefix[0]) + (prefix[n - 2] - prefix[i - 1]));
}
//벌 벌 꿀통->왼쪽 벌과 꿀통을 양쪽에 넣고 중간 벌의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[n - 1] - honey[0] - honey[i]) + (prefix[n - 1] - prefix[i]));
}
//꿀통 벌 벌->중간 벌의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[n - 2] - honey[i]) + prefix[i - 1]);
}
cout << ans;
return 0;
}
1. 문제
n개의 장소와 각 장소에 있는 꿀의 양이 주어진다. 이 중 서로 다른 두 장소를 골라 벌을 배치하고, 벌과 다른 곳에 위치한 장소를 골라 벌통을 배치하려고 한다. 벌은 벌통 방향으로 가면서 꿀을 따는 데, 다음의 규칙을 따른다.
- 두 마리가 모두 지나간 장소에서는 두 마리 모두 표시된 양 만큼의 꿀을 딴다. (벌통이 있는 장소에서도 같다.)
- 벌이 시작한 장소에서는 어떤 벌도 꿀을 딸 수 없다.
각 벌이 따는 꿀의 합을 최대로 하려고 할 때, 꿀의 양을 구하라.
2. 풀이
벌이 따는 꿀의 양은 기본적으로 벌이 위치한 장소의 다음 장소에서 벌통까지의 꿀의 양의 합이다. n이 10만까지이고, 경우의 수가 많으므로 누적 합을 사용하여 풀어야 한다.
for (int i = 0; i < n; i++) {
cin >> honey[i];
if (i == 0) {
prefix[i] = honey[i];
} else {
prefix[i] = prefix[i - 1] + honey[i];
}
}
꿀의 양을 입력받으면서 누적 합을 구해준다.
벌과 벌통의 위치는 세 가지 케이스로 나눌 수 있다.
1. 벌 꿀통 벌
회색 장소가 벌의 위치, 검은색 장소가 벌통의 위치이다. 왼쪽에 배치한 벌은 9+4=13, 오른 쪽에 배치한 벌은 9+4+1+4=18, 총 31의 꿀을 모을 수 있다. 벌이 자신의 바깥쪽에 위치한 꿀을 채취하지 못하는 걸 막기 위해서는 이와 같이 벌을 양쪽 끝에 배치해야 최댓값을 기대할 수 있다.
//벌 꿀통 벌->꿀통의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[i] - prefix[0]) + (prefix[n - 2] - prefix[i - 1]));
}
이 식과 같이 꿀통의 위치를 옮겨가면서 왼쪽 벌의 위치+1~벌통의 위치, 벌통의 위치~오른쪽 벌의 위치 -1까지의 꿀의 합을 각각 더해 준다.
2. 벌 벌 꿀통
1의 케이스와 같은 원리로 왼쪽 벌이 왼쪽 끝보다 안쪽에 있으면 바깥쪽의 꿀을 채취할 수 없고, 꿀통이 안쪽에 있으면 두 벌 모두 꿀통보다 오른 쪽에 있는 꿀을 채취할 수 없으므로 왼쪽 벌과 꿀통을 양쪽 끝에 배치하고, 가운데의 벌의 위치를 옮겨가면서 계산한다.
//벌 벌 꿀통->왼쪽 벌과 꿀통을 양쪽에 넣고 중간 벌의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[n - 1] - honey[0] - honey[i]) + (prefix[n - 1] - prefix[i]));
}
왼쪽 벌은 왼쪽 벌의 위치+1~벌통의 위치의 꿀의 합을 계산하는 데, 중간 벌의 위치에서는 2번 규칙에 의해 꿀을 딸 수 없으니 빼준다. 중간 벌은 중간 벌의 위치+1~벌통의 위치의 꿀의 합을 계산한다. 둘의 합을 더하면 꿀의 양을 계산할 수 있다.
3. 꿀통 벌 벌
//꿀통 벌 벌->중간 벌의 위치를 조정해가며 계산
for (int i = 1; i < n - 1; i++) {
ans = max(ans, (prefix[n - 2] - honey[i]) + prefix[i - 1]);
}
2번과 같은 방법으로 계산해준다. 중간 벌은 맨 왼쪽(벌통의 위치)~벌의 위치-1까지 꿀을 더하고, 오른쪽 벌은 맨 왼쪽~벌의 위치-1(n-2)까지 더하는 데, 중간 벌이 위치한 장소의 꿀은 빼준다.
세 케이스를 구해 max 함수로 최댓값을 구하여 ans에 저장했으니 이를 출력하면 정답을 구할 수 있다.
'Coding Test' 카테고리의 다른 글
백준 19539 사과나무(C++) (7) | 2024.07.15 |
---|---|
백준 11509 풍선 맞추기(C++) (0) | 2024.07.13 |
백준 20117 호반우 상인의 이상한 품질 계산법(C++) (0) | 2024.07.11 |
백준 16206 롤케이크 (1) | 2024.07.10 |
백준 1474 밑 줄 (1) | 2024.07.09 |