[백준] 14003번 가장 긴 증가하는 부분 수열 5 (C++)
문제Permalink
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 30, 50} 이고, 길이는 4이다.
입력Permalink
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)
예제 입력 1Permalink
6
10 20 10 30 20 50
출력Permalink
첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다. 둘째 줄에는 가장 긴 증가하는 부분 수열을 출력한다. 그러한 수열이 여러가지인 경우 아무거나 출력한다.
예제 출력 1Permalink
4
10 20 30 50
풀이Permalink
문제 해결 방법Permalink
이 문제는 LIS(Longest Increasing Subsequence) 알고리즘을 최적화하여 해결할 수 있습니다. 주요 해결 단계는 다음과 같습니다:
- 이분 탐색을 이용한 LIS:
- 현재까지의 증가 수열을 유지하면서 새로운 원소를 적절한 위치에 삽입
- 세그먼트 트리를 이용하여 최적화
- 경로 복원:
- 각 원소의 위치를 저장하여 실제 수열을 역추적
- 마지막 원소부터 시작하여 LIS를 구성
이 알고리즘의 시간 복잡도는 O(N log N)입니다.
코드Permalink
#include<stdio.h>
#include<algorithm>
using namespace std;
int n, nn;
int idx[2100000];
int path[1000001];
int dp[1000001];
int a[1000001];
pair<int, int> st[1000001];
int get_max(int l, int r)
{
l += nn - 1;
r += nn - 1;
int mx = 0;
while (l <= r)
{
if (l & 1)mx = max(mx, idx[l++]);
if (~r & 1)mx = max(mx, idx[r--]);
l >>= 1;
r >>= 1;
}
return mx;
}
void edit(int i, int v)
{
i += nn - 1;
idx[i] = v;
i >>= 1;
while (i)
{
idx[i] = max(idx[i * 2], idx[i * 2 + 1]);
i >>= 1;
}
}
int main()
{
int i;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
// a[i] 를 기준으로 오름차순 정렬. a[i]가 같다면 i기준 내림차순 정렬
st[i] = { a[i],-i };
}
////기존 방식////
/*
int j, k;
for (i = 1; i <= n; i++)
{
k = 0;
for (j = 1; j < i; j++)
{
if (a[j] < a[i])
k = max(k, dp[j]);
}
dp[i] = k + 1;
}
*/
/////////////////
//index tree 셋팅 (초기화는 필요 x)
for (nn = 1; nn < n; nn *= 2);
// 정렬
sort(st + 1, st + n + 1);
int mx = 0, x;
for (i = 1; i <= n; i++)
{
// i번째 데이터의 index
x = -st[i].second;
// dp[x] = 1 ~ x-1 구간의 최댓값 +1
dp[x] = get_max(1, x - 1) + 1;
// dp값을 index tree에 업데이트
edit(x, dp[x]);
// 최댓값 저장
mx = max(dp[x], mx);
}
printf("%d\n", mx);
int mxx = mx;
int inf = 1e9;
for (i = n; i >= 1; i--)
{
if (dp[i] == mxx && a[i] < inf)
{
path[mxx] = i;
inf = a[i];
mxx--;
}
}
for (i = 1; i <= mx; i++)
printf("%d ", a[path[i]]);
return 0;
}
댓글남기기