Tesseractjh
한 걸음씩
Tesseractjh
전체 방문자
오늘
어제
  • 전체 (293)
    • IT (30)
      • JavaScript (7)
      • TypeScript (5)
      • React (5)
      • Next.js (3)
      • MongoDB (2)
      • Webpack (2)
      • HTML & CSS (1)
      • Git (0)
      • AWS (1)
      • 기타 (4)
    • 연습장 (259)
      • 백준(BOJ) 문제풀이 (185)
      • 프로그래머스 문제풀이 (61)
      • LeetCode 문제풀이 (2)
      • HackerRank 문제풀이 (7)
      • 낙서장 (3)
      • 기타 (1)
    • 프로젝트 (3)
      • 지뢰피하기 (1)
      • 키릴-라틴 문자 변환기 (1)
      • Flex & Grid (1)
    • 멋쟁이사자처럼 프론트엔드 스쿨 1기 (1)
      • 일기 & 회고록 (1)

인기 글

티스토리

hELLO · Designed By 정상우.
Tesseractjh

한 걸음씩

연습장/백준(BOJ) 문제풀이

[백준 2104] 부분배열 고르기 with Node.js

2021. 7. 22. 15:03

문제 링크

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까지의 최솟값을 곱한 것이

www.acmicpc.net

풀이

const input = require("fs").readFileSync("/dev/stdin").toString().trim().split(/\s/);
const N = +input[0];
const A = input.slice(1).map(v => +v);
const sums = Array(N+1).fill(0);
A.forEach((v, i) => sums[i+1] = sums[i] + v);

const dnq = function (l, r) {
    if (l == r) return A[l]*A[l];

    const m = Math.floor((l+r)/2);
    const LEFT = dnq(l, m);
    const RIGHT = dnq(m+1, r);

    let tmpL = m;
    let tmpR = m+1;
    let low = Math.min(A[tmpL], A[tmpR]);
    let MID = (sums[tmpR+1]-sums[tmpL])*low;
    let tmp_score;

    while (tmpL > l || tmpR < r) {
        if (tmpL > l && (tmpR === r || A[tmpL-1] > A[tmpR+1])) {
            low = Math.min(low, A[--tmpL]);
            tmp_score = (sums[tmpR+1]-sums[tmpL])*low;
        } else {
            low = Math.min(low, A[++tmpR]);
            tmp_score = (sums[tmpR+1]-sums[tmpL])*low;
        }
        MID = Math.max(MID, tmp_score);
    }

    return Math.max(LEFT, RIGHT, MID);
};

console.log(dnq(0, N-1));

분할정복을 활용하여 먼저 전체 구간을 반으로 나눈다.

반으로 나눈 왼쪽 구간과 오른쪽 구간은 재귀호출을 통해 최댓값을 각각 LEFT와 RIGHT에 저장한다.

 

왼쪽 구간과 오른쪽 구간에 걸쳐 있는 경우를 생각해보자.

두 구간에 걸쳐 있는 최댓값을 찾으려면, 왼쪽 구간의 가장 마지막 요소와 오른쪽 구간의 첫 번째 요소 두 개를 포함하는 최댓값을 찾아야 한다.

문제 예시에 나와 있는 3 1 6 4 5 2를 입력했다면, 6과 4를 포함하는 최댓값을 찾아야 한다.

 

이제부터 왼쪽 또는 오른쪽으로 숫자를 더 늘려가며 더 큰 값이 나올 수 있는지 확인해야 한다.

이 때 왼쪽과 오른쪽 중 더 큰 것부터 포함시키며 점수를 확인한다.

6과 4의 양 옆에 1과 5가 있다.

이 중에 더 큰 5부터 먼저 포함시켜서 6 4 5로 점수를 계산한다.

그 다음에는 1과 2중에서 2를 포함시켜 6 4 5 2로 점수를 계산하고,

오른쪽 구간에 남은 수가 없기 때문에 이제부터는 왼쪽 구간 수를 하나씩 포함하며 점수를 계산한다.

(6 4 ▶ 6 4 5 ▶ 6 4 5 2 ▶1 6 4 5 2 ▶ 3 1 6 4 5 2)

 

이렇게 해서 구한 최댓값을 MID에 저장하고

최종적으로 LEFT, RIGHT, MID 중에 최댓값을 반환한다.

 

여기서 점수를 계산할 때, A[tmpL]부터 A[tmpR]까지의 합을 그 때 그 때 구하지 않고,

미리 sums 배열을 만들어서 누적합을 저장해놓았다.

처음에 이 sums 배열을 만들지 않고 점수를 계산하였더니 시간 초과로 통과하지 못하였다.

저작자표시 비영리 (새창열림)

'연습장 > 백준(BOJ) 문제풀이' 카테고리의 다른 글

[백준 5904] Moo 게임 with Python  (2) 2021.07.24
[백준 18111] 마인크래프트 with Node.js  (0) 2021.07.23
[백준 10830] 행렬 제곱 with Python  (0) 2021.07.21
[백준 1074] Z with Python  (0) 2021.07.08
[백준 1780] 종이의 개수 with Node.js  (0) 2021.07.08
    '연습장/백준(BOJ) 문제풀이' 카테고리의 다른 글
    • [백준 5904] Moo 게임 with Python
    • [백준 18111] 마인크래프트 with Node.js
    • [백준 10830] 행렬 제곱 with Python
    • [백준 1074] Z with Python
    Tesseractjh
    Tesseractjh
    바닐라 자바스크립트를 좋아하는 개발자입니다

    티스토리툴바