본문 바로가기

Problem Solving/BOJ 백준

[ BOJ 백준 2104번 - 부분배열 고르기 ] 해설 및 코드

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

 

2104번: 부분배열 고르기

문제 크기가 N(1≤N≤100,000)인 1차원 배열 A[1], …, A[N]이 있다. 어떤 i, j(1≤i≤j≤N)에 대한 점수는, (A[i]+…+A[j])×Min{A[i], …, A[j]}가 된다. 즉, i부터 j까지의 합에다가 i부터 j까지의 최솟값을 곱한 것이 점수가 된다. 배열이 주어졌을 때, 최대의 점수를 갖는 부분배열을 골라내는 프로그램을 작성하시오. 입력 첫째 줄에 정수 N이 주어진다. 다음 줄에는 A[1], …, A[N]을 나타내는 정수들

www.acmicpc.net

목적

어떤 i, j(1≤i≤j≤N)에 대하여, (A[i]+…+A[j])×Min{A[i], …, A[j]} 와 같은 식의 최대값을 구한다.

 

접근법

1. 스위핑 알고리즘으로 O(n)에 문제를 해결해보자.(백준 1725 - 히스토그램 문제처럼 분할 정복 알고리즘으로도 접근 가능하다.)

2. 부분합은 전처리 과정을 통해, 스위핑 알고리즘 적용시 O(1)의 시간복잡도에 해결하자.

 

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
31
32
#include<iostream>
 
using namespace std;
typedef long long ll;
 
int a[100002= {-1};
ll psum[100001= {0};
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    
    int n; cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        psum[i] = psum[i - 1+ a[i];
    }
    a[++n]=0;
    
    ll ret=0;
    int s[100002={0},top=0;
    for (int i = 1; i <= n; ++i){
        while(a[s[top]]>=a[i]){
            int height=a[s[top--]];
            ll val=height*(psum[i-1]-psum[s[top]]);
            if(ret<val)ret=val;
        }
        s[++top]=i;
    }
    cout<<ret;
}
 
 
 

문제 설명과 코드에 대한 피드백은 언제나 환영합니다.

 다양한 의견 댓글로 남겨주세요.