Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

dh-winternagi 님의 블로그

(6549) 히스토그램에서 가장 큰 직사각형 본문

백준 (C++)/Solve

(6549) 히스토그램에서 가장 큰 직사각형

dh-winternagi 2026. 4. 18. 13:55

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

단계별로 풀어보기

24단계(분할 정복) 9번째

 

 

 

단계별 문제에서 처음으로 등장하는 플래티넘 문제다. 그만큼 매우 어렵다.

분할 정복으로 푸는 방법을 간단하게 설명하면

1) 구간 (i,j)에 대해 i=j가 아니라면 가운데를 기준으로 자른다. 맞다면 현재 구간의 높이(=구간에서 직사각형의 최대 넓이)를 리턴한다.

2) 가운데를 기준으로 자른 왼쪽 구간과 오른쪽 구간 각각의 최대값을 재귀를 이용해 구한다.

3) 왼쪽 구간과 오른쪽 구간을 둘 다 포함하는 직사각형이 최대 넓이일 수도 있으므로 이를 구한다.

4) 2번과 3번에서 구한 최댓값을 전부 비교해 가장 큰 값을 리턴한다.

3번에서 구간 전체를 탐색해야 하므로 O(N)이 걸리고, 분할 정복에 O(log N)이 걸리므로

코드의 전체 시간복잡도는 O(N log N)이다.

 

 

 

#include <iostream>
#include <vector>
using namespace std;

void solve(int n){
  vector<long> v(n);
  
  for(int i=0;i<n;i++)  cin >> v[i];
  
  auto func= [&](auto self, int lo, int hi) -> long {
    if(lo==hi)  return v[lo];
    
    int mid= (lo+hi)/2;
    
    int l= mid, r= mid;
    long h= v[mid], area= v[mid];
    
    while(lo<l && r<hi){
      if(v[l-1]<v[r+1]){
        r++;
        h= min(h, v[r]);
      }else{
        l--;
        h= min(h, v[l]);
      }
      
      area= max(area, h*(r-l+1));
    }
    
    while(lo<l){
      l--;
      h= min(h, v[l]);
      area= max(area, h*(r-l+1));
    }
    
    while(r<hi){
      r++;
      h= min(h, v[r]);
      area= max(area, h*(r-l+1));
    }
    
    return max(area, max(self(self, lo, mid), self(self, mid+1, hi)));
  };
  
  cout << func(func, 0, n-1) << "\n";
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  int n;
  
  while(true){
    cin >> n;
    
    if(!n)  break;
    
    solve(n);
  }
  
  return 0;
}

'백준 (C++) > Solve' 카테고리의 다른 글

(10816) 숫자 카드  (0) 2026.04.18
(1920) 수 찾기  (0) 2026.04.18
(11444) 피보나치 수 6  (0) 2026.04.18
(10830) 행렬 제곱  (0) 2026.04.18
(2740) 행렬 곱셈  (0) 2026.04.18