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


수열에서 연속 부분 수열 두개를 골라 그 곱이 가장 클 때 얼마나 클지 알아내야 한다.


연속 부분 수열이 얼마나 클지를 알아내는 방법은 디피 문제를 풀 때 쉽게 접할 수 있는 문제다.


dp[x]를 x번째 인자를 포함한 부분 수열 중 합이 가장 큰 수를 저장하게 정의해 놓으면,


dp[x]는 dp[x-1]이 음수인 경우와 양수인 경우로 나눠 원타임에 값이 정해진다.



또한 새로운 디피 배열 lmax를 정의할 수 있게 되는데,


이번엔 lmax[x]는 x번째 인자를 반드시 포함하지 않아도, x까지 수열의 부분 수열 중 합이 가장 큰 수를 저장한다고 정의해 놓으면,


lmax[x] = max(lmax[x-1], dp[x])로 원타임에 값이 정해진다.


즉 x가 포함되던지 안되던지 두 케이스 중 큰 값으로 정해지는 것이다.



이를 응용해서 왼쪽에서 부터, 오른쪽에서 부터, 최대합 부분수열, 최소합 부분수열을 모두 n타임에 구할 수 있다.


그러고 난 다음 부분 수열 두 개로 나눌 기준점을 n개 중에 골라서 비교하는 작업도 n타임에 수행할 수 있다.


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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
 
int n;
ll arr[100001];
 
ll dmin[100001], dmax[100001];
ll lmin[100001], lmax[100001];
ll rmin[100001], rmax[100001];
 
int main() {
    cin.tie(0);
    ios_base::sync_with_stdio(0);
 
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> arr[i];
    }
 
    lmin[1= lmax[1= dmin[1= dmax[1= arr[1];
 
    for (int i = 2; i <= n; ++i) {
        if (dmax[i - 1< 0)
            dmax[i] = arr[i];
        else
            dmax[i] = dmax[i - 1+ arr[i];
 
        if (dmin[i - 1> 0)
            dmin[i] = arr[i];
        else
            dmin[i] = dmin[i - 1+ arr[i];
 
        lmin[i] = min(lmin[i - 1], dmin[i]);
        lmax[i] = max(lmax[i - 1], dmax[i]);
    }
 
    memset(dmin, 0sizeof(dmin));
    memset(dmax, 0sizeof(dmax));
 
    rmin[n] = rmax[n] = dmin[n] = dmax[n] = arr[n];
 
    for (int i = n - 1; i >= 1--i) {
        if (dmax[i + 1< 0)
            dmax[i] = arr[i];
        else
            dmax[i] = dmax[i + 1+ arr[i];
 
        if (dmin[i + 1> 0)
            dmin[i] = arr[i];
        else
            dmin[i] = dmin[i + 1+ arr[i];
 
        rmin[i] = min(rmin[i + 1], dmin[i]);
        rmax[i] = max(rmax[i + 1], dmax[i]);
    }
 
    ll ans = LLONG_MIN;
    for (int i = 1; i < n; ++i) {
        ans = max(ans, lmin[i] * rmin[i + 1]);
        ans = max(ans, lmin[i] * rmax[i + 1]);
        ans = max(ans, lmax[i] * rmin[i + 1]);
        ans = max(ans, lmax[i] * rmax[i + 1]);
    }
 
    cout << ans;
}
cs


'알고리즘 > Dynamic Programming 동적계획법' 카테고리의 다른 글

백준) 2965 캥거루 세마리  (0) 2018.02.06
백준) 2156 포도주 시식  (0) 2018.02.04
백준) 1463 1로 만들기  (0) 2018.02.02
백준) 2579 계단 오르기  (0) 2018.02.02
백준) 1149 RGB거리  (0) 2018.02.01

+ Recent posts