반응형

문제 출처 :


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



알고리즘 분석 :


문제 해결에 필요한 사항

1. lis 알고리즘 :: http://www.crocus.co.kr/583

2. lds 알고리즘 :: http://www.crocus.co.kr/669


이 문제는 lis + lds - 1이 정답이 된다.


왜 lis + lds - 1이 정답일까?


9

5 6 4 7 3 8 2 9 1 를 보자.


5 기준으로 볼때 5 6 7 8 9가 올 수 있고 5 앞에는 1 2 3 4 5가 올 수 있다.

결국 1 2 3 4 5 6 7 8 9가 올 수 있으므로 lis + lds를 하고 5가 중복되니 -1을 해준 9가 답이 된다.


우선 이 문제는 DP로 해결하면 가장 쉽게 해결 할 수 있다.


그리고 DP는 O(n^2)으로 해결이 되지만, lower_bound 방식을 이용하면 O(n^2*lgn)의 시간이 걸리게 된다.


하지만 DP가 아닌 로어바운드로 어떻게 문제를 해결하는지 알기 위해 풀이를 쓰고자 한다.


lis를 구할 때는 lower_bound를 쓰되 , 현재 idx에 값을 고정시키고 현재 idx값보다 큰 값을 하나 찾아 그 값을 기준으로 lis를 조사한다.


이때 현재 idx값보다 작은 값이 나타나면 모순이 일어나므로 continue를 해주며 값을 조사해준다.


예를들어 5 6 1 2 4가 있다 보자.


현재 5를 고정 시키고 그다음 6이 나타나 5 6 이 현재 lis에 있다.


그런데 1이 와버리면 6자리에 1이 들어가게 되어 5 1이 되고 결국 5 1 2 4가 lis가 되어버린다.


실제 lis는 5 6이 되어야하는데 결국 이상한 lis가 형성되므로 현재 인덱스에 해당하는 값보다 작은 값이 나타나면 continue를 해준다.


lds도 마찬가지이다. 대신 lds를 구할 때는 lower_bound를 쓸 수 없으므로 직접 lds용 lower_bound를 형성한다.















소스 코드 : 


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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
 
using namespace std;
 
int n;
 
int lis(int here, vector<int> vc)
{
    vector<int> lis;
    int plis = 1;
 
    // 현재 idx값 고정
    lis.push_back(vc[here]);
 
    // 현재 idx값 보다 큰 값이 존재하면 하나 push
    int i;
    for (i = here + 1; i < n; i++)
        if (lis[0< vc[i])
        {
            lis.push_back(vc[i]);
            plis++;
            i++;
            break;
        }
 
    // 그 다음 값부터 조사
    for (i; i < n; i++)
    {
        // 현재 idx값보다 작은 값이 나타나면 현재 기준 lis에 모순이 일어나기에 continue
        if (lis[0> vc[i])
            continue;
 
        if (lis.back() < vc[i])
        {
            lis.push_back(vc[i]);
            plis++;
        }
        
        else
        {            
            auto it = lower_bound(lis.begin() + 1, lis.end(), vc[i]) - (lis.begin());
            lis[it] = vc[i];
        }
    }
 
    return plis;
}
 
int getLds(vector<int> lds, int start, int end, int target)
{
    int mid;
 
    while (start < end)
    {
        mid = (start + end) / 2;
 
        if (lds[mid] > target)
            start = mid + 1;
        else
            end = mid;
    }
    return end + 1;
}
 
int lds(int here, vector<int> vc)
{
    vector<int> lds;
    int plds = 1;
 
    // 현재 idx값 고정
    lds.push_back(vc[here]);
 
    // 현재 idx값 보다 작은 값이 존재하면 하나 push
    int i = 0;
    for (i = here + 1; i < n; i++)
        if (lds[0> vc[i])
        {
            lds.push_back(vc[i]);
            plds++;
            i++;
            break;
        }
 
    // 그 다음 값부터 조사
    for (i; i < n; i++)
    {
        // 현재 idx값보다 큰 값이 나타나면 현재 기준 lis에 모순이 일어나기에 continue
        if (lds[0< vc[i])
            continue;
    
        if (lds.back() > vc[i])
        {
            lds.push_back(vc[i]);
            plds++;
        }
 
        else
        {
            int pos = getLds(lds, 1, plds, vc[i]);
            lds[pos - 1= vc[i];
        }
 
    }
 
    return plds;
}
 
int main()
{
    scanf("%d"&n);
 
    vector<int> vc(n);
 
    for (int i = 0; i < n; i++)
        scanf("%d"&vc[i]);
 
    int ans = 0;
    for (int i = 0; i < n; i++)
    {
        int cntLis = lis(i, vc);
        int cntLds = lds(i, vc);
 
        ans = max(ans, cntLis + cntLds - 1);
    }
 
    printf("%d", ans);
 
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus

반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

[2550번] 전구  (0) 2017.07.28
[2548번] 대표 자연수  (0) 2017.07.28
[2999번] 비밀 이메일  (0) 2017.07.22
[3977번] 축구 전술  (0) 2017.07.22
[4196번] 도미노  (0) 2017.07.22