https://www.acmicpc.net/problem/14003
문제
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.
입력
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)
출력
첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.
둘째 줄에는 정답이 될 수 있는 가장 긴 증가하는 부분 수열을 출력한다.
문제 풀이
O(nlogn)으로 푸는 LIS 문제.
12738번의 가장 긴 증가하는 부분 수열3과 유사하지만, 정답이 되는 부분 수열까지 출력해야 한다. 12738번을 그대로 사용해서 해당 dp 벡터의 값을 출력하면 될 것 같지만, 그렇지 않다.
O(nlogn)으로 푸는 LIS 문제는 dp 벡터에 저장되는 숫자들은 인덱스 0은 길이 1로 얻을 수 있는 가장 작은 숫자, 인덱스 1은 길이 2로 얻을 수 있는 가장 작은 숫자..등의 형식으로 값이 저장되어 있다. 문제는 그 가장 작은 숫자를 저장할 때 원본 배열의 인덱스 순서까지 고려하지 않는다는 점이다. 따라서 저장되는 값은 다르지만, 그 길이는 LIS의 최대 길이가 된다.
실제 배열의 가장 긴 증가하는 부분 수열을 구하려면 역추적을 사용해야 한다. 추가로 크기 N짜리 indexes 배열을 만들어 dp 벡터를 구하면서 indexes[i]에 해당 값으로 얻을 수 있는 dp 벡터의 인덱스를 저장한다.
예시로 예제 입력 1을 보자.
10 20 10 30 20 50
처음인 10은 dp 벡터에 추가된다. 따라서 indexes[0]은 0이 된다.
20은 벡터의 마지막인 10보다 크므로 dp 벡터에 추가되고, indexes[1]은 1이 된다.
10은 동일하므로 indexes[2]는 0이 된다.
30은 벡터의 마지막인 20보다 크므로 dp 벡터에 추가되고, indexes[3]은 2가 된다.
20은 두번째 원소와 같으므로 indexes[4]는 1이 된다.
50은 벡터의 마지막인 30보다 크므로 dp 벡터에 추가되고, indexes[4]은 3가 된다.
dp 벡터를 통해 크기를 알고 있으므로 indexes를 끝부분부터 처음까지 역으로 탐색해 부분 수열을 얻어내면 된다.
아래는 코드.
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
int main()
{
cin.tie(NULL);
ios::sync_with_stdio(false);
int N;
cin >> N;
int* arr = new int[N];
int* indexes = new int[N];
stack<int> answer;
for (int i = 0;i < N; i++)
{
cin >> arr[i];
indexes[i] = 0;
}
vector<int> v;
indexes[0] = 0;
v.push_back(arr[0]);
for (int i = 1; i < N; i++)
{
if (arr[i] > v.back())
{
v.push_back(arr[i]);
indexes[i] = v.size() - 1;
}
else
{
int index = lower_bound(v.begin(), v.end(), arr[i]) - v.begin();
v[index] = arr[i];
indexes[i] = index;
}
}
int currentFindIndex = v.size() - 1;
for (int i = N - 1; i >= 0; i--)
{
if (indexes[i] == currentFindIndex)
{
currentFindIndex--;
answer.push(arr[i]);
}
}
cout << v.size() << "\n";
while (!answer.empty())
{
cout << answer.top() << " ";
answer.pop();
}
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준 14921] 용액 합성하기 (C++) (0) | 2024.08.03 |
---|---|
[백준 2688] 줄어들지 않아 (C++) (0) | 2024.08.02 |
[백준 17359] 전구 길만 걷자 (C++) (0) | 2024.07.31 |
[백준 20125] 쿠키의 신체 측정 (C++) (0) | 2024.07.30 |
[백준 1417] 국회의원 선거 (C++) (0) | 2024.07.29 |