문제

  • 크기가 \(N(1 \le N \le 32000)\)인 수열 \(A(-1000000000\le A_i \le 10000000000)\)이 주어진다.
  • 수열 \(A\)의 LIS의 길이와, 정답이 될 수 있는 LIS 중 하나를 출력해야 한다.

풀이

  • Binary search를 사용한 O(nlogn)의 LIS 풀이를 사용했다.
코드
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
#include <algorithm>
#include <iostream>
#include <stack>
#include <vector>
#define v vector

using namespace std;
using vi = vector<int>;
using ll = long long;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, lidx;
    cin >> n;
    vi ar(n, 0), lis, ari(n, 0);
    for (int i = 0; i < n; i++)
        cin >> ar[i];
    lis.push_back(ar[0]);
    for (int i = 1; i < n; i++) {
        if (lis.back() < ar[i]) {
            lis.push_back(ar[i]);
            ari[i] = lis.size() - 1;
            continue;
        }
        int ci = upper_bound(lis.begin(), lis.end(), ar[i]) - lis.begin();
        if (ci > 0 && lis[ci - 1] == ar[i]) {
            ari[i] = ci - 1;
            continue;
        }
        lis[ci] = ar[i];
        ari[i] = ci;
    }
    cout << lis.size() << endl;
    lidx = lis.size() - 1;
    stack<int> res;
    for (int i = n - 1; i >= 0; i--) {
        if (ari[i] == lidx) {
            res.push(ar[i]);
            lidx--;
            if (lidx == -1) break;
        }
    }
    while (!res.empty()) {
        cout << res.top() << ' ';
        res.pop();
    }
    return 0;
}

풀고나서

  • 처음 AC를 받는 코드는 204ms가 걸렸다. 다른 사람들의 풀이를 보고 아래와 같이 적당하게 이상적인 풀이까지 시간을 줄여보았다.
방법 메모리 시간
기존 18220KB 204ms
방법 1 18220KB 192ms
방법 2 18220KB 184ms
  • 방법 1 : if…else를 if-continue로 바꿨다.
    • 이전에는 미세하게 차이가 나서 확신하지 못했는데, 이번에도 바꾸면서 효과를 봐서, 확실히 성능 차이가 있다는 것을 알게 되었다.
  • 방법 2 : LIS의 마지막 원소로 추가하는 경우가 upper_bound 구문보다 먼저 실행되게 커팅했다.

Leave a comment