본문 바로가기
백준

백준 14003 가장 긴 증가하는 부분 수열 5

by 조재범 2021. 6. 3.

algorithm : DP , lower_bound

 

해설

O(N * N) LIS로 풀면 시간 초과가 나오는 문제이다 그렇기 때문에 다른 방법을 생각해보아야 한다

O(N log N) 시간을 줄여야 한다. lower_bound = O(log N)

 

초기값

10 50 45 60 35 100

 

LIS

10          

10이 LIS 중 가장 큰 값이기 때문에 10을 push_back 합니다

 

                                                        ↓

 

10 50        

50이 LIS중 가장 큰 값이기 때문에 50을 push_back 합니다

 

                                                        ↓

10 45        

45는 LIS 중 가장 큰 값이 아닙니다 10 보다는 크고 50보다는 작은 수입니다 그렇기 때문에 45보다 작은

수중 가장 가까운 수인 10 뒤 2번째 배열에 50을 빼고 45를 추가한다

 

                                                        ↓

10 45 60      

60이 LIS 중 가장 큰 값이기 때문에 60을 push_back 합니다

 

                                                        ↓

 

10 35 60      

30은 배열중 자기보다 작고 30이랑 가까운 10 뒤에 45를 지우고 35를 넣는다

 

                                                        ↓

10 35 60 100        

100이 LIS 중 가장 큰 값이기 때문에 100을 push_back 합니다

 

이제 여기서 얻은 LIS를 그냥 출력하면 오답이 나온다 자기가 어디서 왔는지 path가 중요하다

 

path를 채우는 방법은 밑에 그림과 같다

35가 들어올 때 경우이다. 자기 배열 처음부터 자기 it까지 거리를 구하면 된다

이런 식으로 구했을 때 밑에 그림처럼 path가 구해진다

path 배열 뒤에서부터 가장 큰 값이 4를 출력한다음 4,3,2,1 순서대로 가면서 그 위치에 있는 arr를 ans 배열에 넣는다

ans는 뒤에서 부터 넣었기 때문에 출력할 때는 reverse 해서 출력했다

#include<bits/stdc++.h>
#define LM 1000000+10
#define INF 199999999
using LL = long long;
using namespace std;

int N;
int arr[LM];
int path[LM];
int chk[LM];
int len;
vector<int> v,ans;

void input(){
    scanf("%d",&N);
    for(int i = 1 ; i <= N ; i++)
        scanf("%d",&arr[i]);
}

void DP(){
    v.push_back(-2000000000);
    for(int i = 1 ; i <= N; i++){
        auto it = lower_bound(v.begin(),v.end(),arr[i]);
        path[i] = it - v.begin();
        if(it == v.end()) v.push_back(arr[i]);
        else *it = arr[i];
    }
}

void trace(){
    int len = v.size() - 1;
    printf("%d\n",len);
    for(int i = N ; i >= 1 ; i--){
        if(len == path[i]){
            ans.push_back(arr[i]);
            len--;
        }
    }
    reverse(ans.begin(),ans.end());
    for(auto a : ans)
        printf("%d ",a);
}
int main(){
    //freopen("input.txt","r",stdin);
    input();
    DP();
    trace();
    return 0;
}

 

'백준' 카테고리의 다른 글

백준 11048 이동하기  (0) 2021.06.05
백준 11722 가장 긴 감소하는 부분 수열  (0) 2021.06.05
백준 12865 평범한 배낭  (0) 2021.06.04
백준 11055 가장 큰 증가 부분 수열  (0) 2021.06.03
백준 1699 제곱수의 합  (0) 2021.06.03