블로그 옮겼습니다
알고스팟) COUNTPALIN 본문
https://algospot.com/judge/problem/read/COUNTPALIN
\( 1\leq{N}\leq{10^6} \)
길이가 N인 문자열 S가 입력으로 주어질 때 팰린드롬인 모든 부분 문자열의 개수를 구하는 문제이다.
이 문제를 푸는 방법은 우선 각 중심마다 최대 팰린드롬의 길이를 구한뒤 그 길이/2 만큼을 모두 더해주는 것이다.
왜냐하면 어떤 중심에서 최대 길이의 팰린드롬이 abccba 라면 같은 중심을 가지는 팰린드롬들은 반지름을 1씩 줄여나가면
모두 팰린드롬이기 때문에다. 이것은 자명하다. 즉, abccba, bccb, cc 이게 다 팰린드롬이 되기 때문에 최대팰린드롬길이/2
의 식이 나오는 것이다. 그리고 중심이 다르면 다른 팰린드롬이라는 것이 자명하기 때문에 모든 각각의 중심에 대해
최대 팰린드롬의 길이를 구하기만 하면 되는 것이다. 그런데 N제한이 크기 때문에 일반적인 O(N^2) 의 방법으로
이것을 계산할 수가 없다. 그렇기 때문에 마나처 알고리즘(Manacher's Algorithm) 을 사용하여 O(N)에 계산하여야 한다.
마나처 알고리즘의 설명은 여기 를 참고하면 된다. 반지름이 짝수인 팰린드롬도 모두 고려하기 위해서는
문자열 사이사이에 # 이나 $ 같은 더미문자를 넣어주어야한다. 이 때 유의해야 할 것은 문자열 aa 는
#a#a# 가 되어 양끝에 #까지 계산된다는 것을 잊지않아야 하는것이다.
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 | #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9+7; const int inf = 0x3c3c3c3c; const long long infl = 0x3c3c3c3c3c3c3c3c; int T,N; string str; int A[2000005]; int main() { cin >> T; while(T--){ str = '~'; string s; cin >> N >> s; for(int i = 1 ; i <= N; i++){ str += '#'; str += s[i-1]; } str += '#'; str += '!'; int R = -1, p; for(int i = 1 ; i < str.size()-1; i++){ if(i <= R) A[i] = min(A[2*p -i], R - i); else A[i] = 0; while(str[i - A[i] - 1] == str[i + A[i] + 1]) A[i]++; if(R < A[i] + i) R = A[i] + i, p = i; } ll ans = 0; for(int i = 1; i < str.size()-1; i++) ans += A[i]/2; cout << ans << endl; } return 0; } | cs |
'Algorithm > Problem Solving' 카테고리의 다른 글
Codeforces Round #420 (Div. 2) D. Okabe and City (0) | 2017.06.26 |
---|---|
CSacademy) Second Minimum (0) | 2017.06.01 |
Codeground) 윤목의 달인 (0) | 2017.05.26 |
Topcoder SRM 522 Div1(Medium) CorrectMultiplication (0) | 2017.05.20 |
BOJ 14276번 도로 건설 (0) | 2017.05.11 |
Comments