레야몬
[C++] 11479번 서로 다른 부분 문자열의 개수 2 - 문자열, 접미사 배열과 lcp 배열 본문
1. 문제
- 문자열 S의 서로 다른 부분 문자열의 개수를 구하시오.
<입력>
- -1- 문자열 \(S(1 \leq L \ leq 1,000,000)\)
<출력>
- -1- 서로 다른 부분 문자열의 개수
2. 재정의
- X
3. 해결 방법
- ababc의 경우 접미사 배열 ababc, babc, abc, bc, c를 (a, ab, aba, abab, ababc), (b, ba, bab, babc), ...가 부분 문자열이 됨을 알 수 있다. 이 때 겹치는 경우는 접미사 배열에서 lcp에 해당하는 경우이다. 따라서 접미사 배열 전체 글자수 \(N(N+1)/2\)에 LCP만큼 빼주면 서로 다른 부분 문자열의 개수를 구할 수 있다.
- 접미사 배열은 Manber-Myers Algorithm으로 LCP array를 구한다.
4. 실수한 점, 개선할 점
- X
<코드>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX_N = 1000002;
// <문제>
// 문자열 S
char S[MAX_N];
// <Manber-Myers Algorithm, LCP Array>
int t, n;
int g[MAX_N], tg[MAX_N], SA[MAX_N], RANK[MAX_N], LCP[MAX_N];
// <입력>
void input() {
cin >> S;
n = (int)strlen(S);
}
bool cmp(int x, int y) {
if(g[x] == g[y])
return g[x+t] < g[y+t];
return g[x] < g[y];
}
// Manber-Myers algorithm
void getSA() {
t = 1;
g[n] = -1;
for(int i=0; i<n; i++) {
SA[i] = i;
g[i] = S[i] - 'a';
}
while(t <= n) {
sort(SA, SA+n, cmp);
tg[SA[0]] = 0;
for(int i=1; i<n; i++) {
if(cmp(SA[i-1], SA[i]))
tg[SA[i]] = tg[SA[i-1]] + 1;
else
tg[SA[i]] = tg[SA[i-1]];
}
for(int i=0; i<n; i++)
g[i] = tg[i];
t <<= 1;
}
}
// LCP array
void getLCP() {
for(int i=0; i<n; i++)
RANK[SA[i]] = i;
int len = 0;
for(int i=0; i<n; i++) {
int k = RANK[i];
if(k) {
int j = SA[k-1];
while(S[j + len] == S[i + len])
len++;
LCP[k] = len;
if(len)
len--;
}
}
}
void solve() {
long long cnt = 0;
getSA();
getLCP();
for(int i=0; i<n; i++)
cnt += n - SA[i] - LCP[i];
cout << cnt;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
input();
solve();
return 0;
}
<문제 바로가기>
https://www.acmicpc.net/problem/11479
11479번: 서로 다른 부분 문자열의 개수 2
첫째 줄에 문자열 S가 주어진다. S는 알파벳 소문자로만 이루어져 있고, 길이는 1,000,000 이하이다.
www.acmicpc.net
<Suffix array와 lcp array>
[C++] 9248번 Suffix Array - 문자열, 접미사 배열과 lcp 배열
1. 문제 길이가 50만보다 작거나 같은 문자열이 주어졌을 때, Suffix Array와 LCP Array를 구하는 프로그램을 작성하시오. -1- 알파벳 소문자로만 이루어진 문자열 S가 주어진다. S의 길이는 50만보다 작
leyamon.tistory.com
※ 궁금한 것 질문 남겨주시면 답변드리겠습니다. 좋아요 눌러주시고 편하게 질문해 주세요.
'알고리즘 > 백준' 카테고리의 다른 글
[C++] 2419번 사수아탕 - DP (1) | 2023.10.19 |
---|---|
[C++] 4008번 특공대 - DP, 볼록 껍질을 이용한 최적화, 누적 합 (0) | 2023.10.15 |
[C++] 3295번 단방향 링크 네트워크 - 이분 매칭 (0) | 2023.10.11 |
[C++] 13725번 RNG - 수학, FFT, NTT, 키타마사 (0) | 2023.08.25 |
[C++] 1067번 이동 - 수학, FFT (0) | 2023.08.23 |
Comments