※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 20052번 문제인 괄호 문자열 ?이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/20052
20052번: 괄호 문자열 ?
괄호 문자열은 '('와 ')'로 이루어진 문자열이고, 올바른 괄호 문자열은 다음과 같이 정의된다. 빈 문자열은 올바른 괄호 문자열이다. S가 올바른 괄호 문자열일 때, (S)도 올바른 괄호 문자열이
www.acmicpc.net
'('를 +1, ')'를 -1로 생각해 prefix sum을 구한 배열 psum을 준비하자.
이 때 어떤 부분문자열 [L,R]이 올바른 괄호문자열이라면 '('로 시작해 ')'로 끝나며 '('과 ')의 개수가 같으므로 psum[R]과 psum[L-1]의 값이 같아야 하고, 어떤 순간에도 등장한 여는 괄호의 수가 닫는 괄호의 수보다 많거나 같아야하므로 min(psum[L..R])의 값이 psum[R]과 같아야 함을 알 수 있다.
위의 두 조건만을 만족하면 부분문자열 s[L..R]은 올바른 괄호문자열이기도 하므로 각 쿼리별로 위 조건들을 체크해 문제를 해결하자. 구간합 배열 및 RMQ를 구하기 위한 트릭(세그먼트트리, sparse table, Arpa's Trick 등)을 이용해 빠르게 해낼 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <string>
using namespace std;
int N, Q; string s;
int arr[100001];
int seg[262145];
int init(int L, int R, int sI) {
if (L < R) return seg[sI] = min(init(L, (L + R) / 2, sI * 2), init((L + R) / 2 + 1, R, sI * 2 + 1));
return seg[sI] = arr[L];
}
int qry(int L, int R, int qL, int qR, int sI) {
if (R < qL || qR < L) return 1000000007;
if (qL <= L && R <= qR) return seg[sI];
return min(qry(L, (L + R) / 2, qL, qR, sI * 2), qry((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1));
}
int ans;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> s; N = s.length();
for (int i = 0; i < N; i++) arr[i + 1] = arr[i] + (s[i] == '(' ? 1 : -1);
init(1, N, 1);
cin >> Q;
while (Q--) {
int L, R; cin >> L >> R;
if (s[L - 1] == '(' && s[R - 1] == ')' && arr[L] == arr[R] + 1 && qry(1, N, L, R, 1) >= arr[R]) ans++;
}
cout << ans;
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 4335 // C++] 숫자 맞추기 (1) | 2023.12.22 |
---|---|
[BOJ 11059 // C++] 크리 문자열 (1) | 2023.12.21 |
[BOJ 13339 // C++] XOR 수열 (1) | 2023.12.19 |
[BOJ 11292 // C++] 키 큰 사람 (1) | 2023.12.18 |
[BOJ 10770 // C++] Rövarspråket (0) | 2023.12.17 |