넘치게 채우기
[BOJ] 27232 - 청소 본문
https://www.acmicpc.net/problem/27232
BOJ - 청소
문제 유형: 집합, 슬라이딩 윈도우
문제 난이도: Gold I
시간 제한: 2초
메모리 제한: 1024MB
문제
준석이는 청소 업체에 다니고 있다. 준석이가 청소할 장소는 번부터 번까지 차례로 번호가 붙은 일렬의 1개의 구역으로 나누어져 있다. 번 구역은 번과 번 구역과 인접해 있어, 두 인접한 구역 사이를 이동하려면 1만큼 걸어야 한다.
각 구역에는 우선순위가 있다. 번 구역의 우선순위 는 이상 이하의 정수로 이 값이 클수록 우선순위가 높다. 임의의 두 구역의 우선순위는 항상 다르다.
준석이는 오늘 이 구역 중 개의 구역을 먼저 청소하려고 한다. 단, 준석이가 청소하는 개의 구역은 반드시 연속해야 한다. 또한 청소할 때 선택한 구역들 내에서는 우선순위가 높은 구역부터 낮은 구역 순서대로 이동하며 청소해야 한다.
두 구역이 멀리 떨어져 있으면 이동하는 시간이 오래 걸리기 때문에, 준석이는 이동 거리의 합이 최소화되도록 연속한 개의 구역을 선택하려고 한다. 이동 거리가 최소가 되도록 구역을 선택했을 때 총 이동 거리를 출력한다.
입력
첫째 줄에 청소할 구역의 길이 과 오늘 청소할 구역의 개수 가 공백으로 구분되어 주어진다.
둘째 줄에 각 구역의 우선순위 이 공백으로 구분되어 주어진다.
출력
개의 구역을 선택했을 때 가능한 총 이동 거리 중 최솟값을 출력한다.
풀이
k개의 구역을 선택을 슬라이딩 윈도우를 통해서 구하면 된다.
그러나, 문제는, 매번 전체 구역의 계산하면, O(N*K)가 걸리고, 이는 TLE이다.
매번의 윈도우마다, O(log K)로 구해내야 하는데, 어떻게 할 수 있을까?
정답은 set을 이용하는 것이다.
set내부에는 레드블랙트리로 구현되어있고, 이전 값과 다음 값을 O(1)에 구할 수 있다.
즉, 매번 전체의 이동거리를 구할 필요 없이, 변경사항에 대해서만 이동거리를 업데이트 시킬 수 있다.
세부구현은 코드 참조..
코드
C++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(int argc, char* argv[]) {
ios::sync_with_stdio(0);
cin.tie(0);
int n, k;
cin >> n >> k;
vector<int> a(n + 1);
vector<int> pos(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
pos[a[i]] = i;
}
set<int> s;
ll ans = 1e18;
ll dist = 0;
auto add = [&](int x) {
auto it = s.insert(x).first;
if (it != s.begin()) {
dist += llabs((ll)pos[*it] - pos[*prev(it)]);
}
auto itn = next(it);
if (itn != s.end()) {
dist += llabs((ll)pos[*it] - pos[*itn]);
}
if (it != s.begin() && itn != s.end()) {
dist -= llabs((ll)pos[*itn] - pos[*prev(it)]);
}
};
auto remove = [&](int x) {
auto it = s.find(x);
auto itn = next(it);
if (it != s.begin()) {
dist -= llabs((ll)pos[*it] - pos[*prev(it)]);
}
if (itn != s.end()) {
dist -= llabs((ll)pos[*it] - pos[*itn]);
}
if (it != s.begin() && itn != s.end()) {
dist += llabs((ll)pos[*itn] - pos[*prev(it)]);
}
s.erase(it);
};
for (int i = 1; i <= n; ++i) {
add(a[i]);
if (s.size() > k) remove(a[i - k]);
if (s.size() == k) ans = min(ans, dist);
}
cout << ans << "\n";
return 0;
}'PS > BOJ' 카테고리의 다른 글
| [BOJ] 6506 - 엘 도라도 (0) | 2025.10.05 |
|---|---|
| [BOJ] 13713 - 문자열과 쿼리 (0) | 2025.10.01 |
| [BOJ] 3217 - malloc (1) | 2025.09.28 |
| [BOJ] 12004 - Closing the Farm(Silver) (1) | 2025.09.27 |
| [BOJ] 1263 - 시간 관리 (0) | 2025.09.26 |