포스트

BOJ 33602 Mascot Naming

sorohue가 PS하는 블로그

BOJ 33602 Mascot Naming

문제 링크입니다.

문제 요약

주어진 $N$개의 패턴 문자열 $S$를 모두 부분수열1로 가지면서, 주어진 특정 금지 문자열 $P$는 부분수열로 갖지 않는 문자열을 찾으세요. 문자열의 길이가 최소가 될 필요는 없습니다.

풀이

$S$들 중에서 $P$를 부분수열로 갖는 것이 있으면 답은 자명히 NO가 됩니다. 이러한 경우를 배제하겠습니다.

$S$들을 $P$를 기준으로 그리디하게 분할합니다. 뭔 말이냐 하면, $S$ 안에서 $P$의 접두사를 찾고, 그 접두사를 칸막이로 생각하는 겁니다. 그러면, 같은 칸에 들어있는 모든 $S$의 조각들을 아무렇게나 나열해도 찾아진 금지 문자열의 접두사 길이가 증가하지 않음을 알 수 있습니다.

따라서 첫 번째 칸에 들어간 모든 문자열 조각을 나열하고, 금지 문자열의 첫 번째 문자를 추가하고, 두 번째 칸의 모든 문자열 조각을 나열하고… 하는 것을 반복하면 $P$를 포함하지 않으면서 모든 $S$를 포함하는 문자열을 얻을 수 있습니다.

코드

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
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

vector<string> s;
vector<char> c[202020];

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);
	int n; cin >> n; s.resize(n);
	for(int i = 0; i < n; i++) cin >> s[i];
	string t; cin >> t;
	string ans = "";
	for(int i = 0; i < n; i++){
		int r = 0;
		for(int j = 0; j < s[i].size(); j++){
			if(s[i][j] == t[r]){
				r++;
				if(r == t.size()) return !(cout << "NO");
			}
			else c[r].push_back(s[i][j]);
		}
	}
	cout << "YES\n";
	for(int i = 0; i < t.size(); i++){
		for(auto x : c[i]) cout << x;
		if(i != t.size()-1) cout << t[i];
	}
}

  1. 어떤 문자열의 부분수열(subsequence)은 그 문자열에서 0개 이상의 문자를 제거한 뒤 남은 문자를 순서를 바꾸지 않고 이어붙인 문자열입니다. ↩︎

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.