Post

[BOJ 1605] 반복 부분문자열

[BOJ 1605] 반복 부분문자열

백준 로고

백준 문제 링크

🔍 문제 분석

자세한 내용은 접미사 배열(Suffix Array) 및 LCP(Longest Common Prefix)접미사 배열 페이지를 참고한다.

  • 반복되는 부분 문자열은 접미사들의 공통 접두사로 이해할 수 있다. 따라서, LCP 배열을 계산한 뒤 배열의 최댓값을 통해서 반복되는 부분 문자열의 최댓값을 계산할 수 있다.

💻 코드 구현

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
#include <bits/stdc++.h>
#define fastio cin.tie(0)->ios::sync_with_stdio(0)

using namespace std;
using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vvll = vector<vector<ll>>;
using vll = vector<ll>;
using vpi = vector<pi>;

constexpr int MAX = 200'000;

int n, sa[MAX], g[MAX], lcp[MAX];
string s;

int main() {
    fastio;

    cin >> n >> s;

    for (int i = 0; i < s.size(); ++i) {
        sa[i] = i;
        g[i] = s[i];
    }

    for (int i = 0; (1 << i) < s.size(); i++) {
        auto cmp = [&] (int lhs, int rhs) {
            if (g[lhs] == g[rhs]) {
                lhs += 1 << i;
                rhs += 1 << i;
                if (lhs < s.size() && rhs < s.size()) {
                    return g[lhs] < g[rhs];
                } 
                return lhs > rhs;
            }
            return g[lhs] < g[rhs];
        };

        sort(begin(sa), begin(sa) + s.size(), cmp);

        int tmp[MAX] = { 0 };
        for (int j = 0; j < s.size() - 1; ++j) {
            tmp[j + 1] = tmp[j] + cmp(sa[j], sa[j + 1]);
        }

        for (int j = 0; j < s.size(); ++j) {
            g[sa[j]] = tmp[j];
        }

        if (g[s.size() - 1] == s.size() - 1) break;
    }

    int k = 0;
    for (int i = 0; i < s.size(); ++i) {
        if (g[i] == 0) continue;
        while (
            (i + k < s.size() && sa[g[i] - 1 < s.size()]) &&
            s[i + k] == s[sa[g[i] - 1] + k]
        ) ++k;
        lcp[g[i]] = k--;
        k = max(k, 0);
    }

    cout << *max_element(begin(lcp), begin(lcp) + s.size());
}

📝 코드 설명

🔧 트러블 슈팅

📚 참고자료

This post is licensed under CC BY 4.0 by the author.