문제
준석이는 영어 단어를 외우려고 한다. 사전에는 N가지 단어가 적혀 있다. 모든 단어는 소문자이다. 단어 안에 있는 모든 알파벳을 알 때, 그 단어를 완전히 안다고 한다.
다음과 같은 쿼리들이 주어진다.
1 x
: 알파벳 x를 잊는다.2 x
: 알파벳 x를 기억해 낸다. 처음에 모든 알파벳을 기억하는 상태고, 모음은 완벽하게 외웠기 때문에 절대 잊지 않는다.
각 쿼리마다 완전히 알고 있는 단어의 개수를 출력하여라.
입력
첫 번째 줄에는 정수 N (1 ≤ N ≤ 10000)과 M (1 ≤ M ≤ 50000)이 주어진다.
다음 N개의 줄에는 문자열이 하나씩 주어진다. 문자열의 길이는 1000을 넘지 않는다.
다음 M개의 줄에는 정수 o와 문자 x가 한 줄씩 주어진다. o는 1, 2중 하나이고, x는 알파벳 소문자이다.
o가 1이면 x를 잊는다는 뜻이고, o가 2면 x를 기억해낸다는 뜻이다. o가 1일 때는 x를 기억하고 있었음이 보장되고, o가 2일 때는 x를 잊고 있었음이 보장된다.
출력
각 쿼리마다 정수 하나를 출력한다.
풀이
떠올릴 수 있는 가장 간단한 방법은 매 순간마다 모든 문자열을 첫 글자부터 검사하는 것이다. 최악의 경우의 시간복잡도를 계산해보면 다음과 같다.
문자열의 최대 갯수 × 문자열의 최대 길이 × M의 최댓값
즉, 10,000 × 1,000 × 50,000 = 500,000,000,000
그러므로 O(NM)
알고리즘을 사용할 경우 문제에서 제시한 시간 제한인 4초
에 돌아가긴 커녕 400초
를 줘도 돌아갈지 의문이다. 따라서 정공법은 통하지 않으므로 비트마스킹
을 활용해야 한다.
하나의 배열에 문자열
대신 이 문자열이 알파벳 중 어떤 알파벳을 포함하고 있는지에 대한 정보만을 저장할 것이다. 비트마스킹
을 이용할 경우 이 정보를 정수형
으로 표현할 수 있다. 하나의 정수를 이진수
로 생각하고, 해당 문자열이 n
번째 알파벳을 포함하고 있을 경우 정수의 n
번째 비트를 켜고, 아닐 경우 켜지 않는다. 따라서 문자열이 입력될 때마다 문자열을 검사하고 비트마스킹
의 결괏값(정수형)을 vector
에 저장한다.
또, 자신이 기억하고 있는 알파벳 또한 비트마스킹
을 이용해 나타낼 수 있다. 똑같이 n
번째 문자열을 잊어버렸을 경우 n
번째 비트를 켜고 아닐 경우 켜지 않는다.
단어를 알고 있는지에 대한 판별은 구현 방식에 따라 두가지로 나뉠 수 있다.
-
자신이 기억하는 문자열 번호를 켰을 경우 다음을 만족해야 아는 단어이다.
AND(단어, 기억) == 단어
-
자신이 잊어버린 문자열 번호를 켰을 경우 다음을 만족하면 모르는 단어이다.
AND(단어, 기억) == TRUE(0이 아니다)
그리고 소소한 팁으로 쿼리가 주어지는 과정에서 입력된 정수 o
에 상관없이 단순히 문자 x
에 대하여 비트를 토글
해도 상관 없으므로 정수 o
에 대한 조건문 처리를 생략할 수 있다.
전체 코드
1 |
|
- Post link: https://blog.yjyoon.dev/boj/2021/01/02/boj-18119/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.