N coding

13576_Prefix와 Suffix 본문

PS

13576_Prefix와 Suffix

NYWOO19 2018. 8. 31. 18:46

해야 하는 것


1. 접두사 == 접미사인 애들의 길이를 찾는다.

2. 걔네가 몇 번 나오는지 찾는다.


내가 문자열과 쿼리를 푼 방법으로 찾았다.


접두사 == 접미사이려면 suffix array를 구했을 때, 

1. 원본 문자열과 lcp가 존재해야하고, 그 lcp의 길이가 자기 자신의 길이와 같아야한다.

2. 그리고 그 cnt는 원본 문자열과 자기 자신의 sa상에서 떨어진 거리이다.


sfx상에서 원본 문자열보다 위쪽에 있는 애들은 그냥 구해주면 된다.

아래쪽에 있는 애들도 그냥 구해주면 된다.

다만 위쪽에 있는 애들이 아래쪽에도 계속 공통으로 나올 수 있고

그 한계는 자신의 길이보다 짧은 lcp가 나올때 이므로 minn값이 바뀔때마다

그 minn길이의 ans가 있는 지 확인한 후 있으면 cnt를 넣어주었다.

더해줄때 하나 뺀 걸 더해주는 이유는

1, 2, 3, 4, 5의 lcp인덱스가 있다면 lcp[1]에 값이 있다는 것은 문자열이 sfx[1]과 sfx[2], 총 두 번 나온다는 것이다.

위쪽에 있는 애들은 [자신의 위치, 원본문자열의 위치]까지 포함한 cnt이고

아래쪽에서 카운트한 것은 또한 [원본문자열의 우ㅣ치, 자신의 위치] 이므로 원본문자열의 위치가 두 번 카운트 되니까 빼줌!




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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
using namespace std;
 
vector<int> sfx, g, ng, lcp, idx, cnt;
string s;
int N, pos[100010];
vector<pair<intint>> ans;
 
bool comp(int& i, int& j, int t) {
    if (g[i] == g[j]) return g[i + t] < g[j + t];
    return g[i] < g[j];
}
 
void getsfx() {
    int lim = max(256, N + 1);
    sfx.clear(); g.clear(); ng.clear(); idx.clear();
    sfx.resize(N); g.resize(N + 1); ng.resize(N + 1); idx.resize(N + 1);
 
    for (int i = 0; i < N; ++i) {
        g[i] = s[i];
        sfx[i] = i;
    }
 
    if (N == 1) g[0= 1;
 
    for (int t = 1; t < N; t <<= 1) {
        cnt.clear(); cnt.resize(lim + 1);
        for (int i = 0; i < N; ++i) cnt[g[min(i + t, N)]]++;
        for (int i = 1; i < lim; ++i) cnt[i] += cnt[i - 1];
        for (int i = N - 1; i >= 0--i) idx[--cnt[g[min(i + t, N)]]] = i;
 
        cnt.clear(); cnt.resize(lim + 1);
        for (int i = 0; i < N; ++i)  cnt[g[i]]++;
        for (int i = 1; i < lim; ++i) cnt[i] += cnt[i - 1];
        for (int i = N - 1; i >= 0--i) sfx[--cnt[g[idx[i]]]] = idx[i];
        
        ng[sfx[0]] = 1;
        for (int i = 1; i < N; ++i) {
            ng[sfx[i]] = ng[sfx[i - 1]] + comp(sfx[i - 1], sfx[i], t);
        }
        for (int i = 0; i < N; ++i) g[i] = ng[i];
        if (ng[sfx[N - 1]] == N) break;
    }
    for (int i = 0; i < N; ++i) --g[i];
}
 
void getlcp() {
    lcp.clear(); lcp.resize(N + 1);
    for (int i = 0, k = 0; i < N; ++i, k = max(k - 10)) {
        if (g[i] == N - 1continue;
        for (int j = sfx[g[i] + 1]; s[j + k] == s[i + k]; ++k);
        lcp[g[i]] = k;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    cin >> s;
    N = s.length();
 
    getsfx();
    getlcp();
 
    int minn = 1e9, cnt = 1;
    for (int i = g[0- 1; i >= 0 && lcp[i]; --i) {
        minn = min(lcp[i], minn);
        cnt++;
        if (N - sfx[i] == minn) ans.push_back({ N - sfx[i], cnt });
    }
 
    sort(ans.begin(), ans.end());
    for (int i = 0; i < ans.size(); ++i) {
        pos[ans[i].first] = i+1;
    }
 
    minn = 100001, cnt = 1;
    for (int i = g[0]; i < N - 1 && lcp[i]; ++i) {
        if (minn > lcp[i]) {
            if (pos[minn]) {
                ans[pos[minn] - 1].second += cnt-1;
                pos[minn] = 0;
            }
            minn = lcp[i];
        }
        cnt++;
        if (N - sfx[i+1== minn) ans.push_back({ N - sfx[i+1], cnt });
    }
    
    if (pos[minn]) {
        ans[pos[minn] - 1].second += cnt-1;
        pos[minn] = 0;
    }
 
    ans.push_back({ N, 1 });
    
    sort(ans.begin(), ans.end());
    cout << ans.size() << '\n';
    for (auto i : ans) {
        cout << i.first << ' ' << i.second << '\n';
    }
 
}
cs


'PS' 카테고리의 다른 글

9376_탈옥  (0) 2018.09.06
1886_프리즌 브레이크/Evacuation  (0) 2018.09.06
2809_아스키거리  (3) 2018.08.30
4217_신성문자  (0) 2018.08.30
15940_네트워크 연결  (2) 2018.08.29