티스토리 뷰

[Codeforces 950C] Zebras - 1600


문제 설명 : 

문제에서 'zebra'라는 특정 문자열을 정의해주는데 이 문자열은 시작과 끝은 반드시 '0'이어야하고, 0과 1이 번갈아가면서 나타나야한다. 그래서 0과 1로만 이루어진 문자열이 주어졌을 때 이 문자열을 적당히 분할하여 모든 substring을 'zebra' 문자열의 조건을 만족시킬 수 있는지 찾는 문제이다.


풀이 : 

0 뒤에는 가장 가까운 1을 찾고, 1 뒤에는 가장 가까운 0을 찾는 방식으로 풀면 된다. 이때 substring의 시작과 끝은 반드시 0이어야하므로, 1로만 시작되거나 1로 끝나는 substring이 발견되었을 때는 불가능처리를 한다. 처음에 이 풀이에 대한 구현을 현재 문자에대한 다음(find)문자를 문자열 끝까지 쭉 훑어서 존재하는지 확인하는 방식으로 짰는데, 이 경우에 000...000 같은 문자열의 경우는 처음 0을 발견하고 1을 찾기위해서 문자열 끝까지 계속 살펴야하므로 시간복잡도가 O(N^2)이다. N이 최대 20만이므로 시간을 더 줄여야만 했다. 

그래서 생각한 방법은 0과 1의 위치(인덱스)를 따로 set에다가 저장해놓고 find문자를 찾을 때는 현재 문자의 인덱스보다 큰 인덱스 중에서 가장 작은 값을 구해야 하므로 set의 lower_bound연산을 이용했다. 그래서 문자를 찾을 때마다 set에서 해당 값은 삭제시킴으로써 set0의 원소가 빌 때까지 실행하면 된다.


주의할 점 : 

예외처리로 고려해야 할 부분이 많다. 앞서 말했다시피 substring이 1로 시작하거나 끝나서는 안되므로 이를 감지하는 조건문을 넣어주고 0의 원소는 0개인데 1의 원소가 아직 남아있는 경우에도 따로 처리를 해주어야 한다.


배운 점 : 

set의 erase와 lower_bound연산의 활용이 중요한 문제였다.

set.erase(원소) : 해당 원소의 값을 삭제, 혹은 set.erase(iterator) : 현재 iterator가 가리키고 있는 원소 삭제


코드 : 


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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<functional>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<assert.h>
#include<stdlib.h>
#include<stack>
using namespace std;
/*********************Contest Template***********************/
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<long long,long long> pll;
typedef pair<int,int> Cord;
#define FASTIO ios_base::sync_with_stdio(false);cin.tie(0);
struct S{
    int a,b; S(){}S(int _a,int _b){
        a=_a;
        b=_b;
    }
    const bool operator<(const S &o) const{
        return a<o.a;
    }
};
priority_queue<int,vector<int>,greater<int>> mpq;
#define SPACE 0
#define NL 1
inline void showAll(vector<int> &v,int NL_or_space){ 
    //0 is space, 1 is NL
    for(int &here:v){
        printf("%d",here);
        printf("%c",(NL_or_space)?'\n':' ');
    }
}
/*********************Contest Template***********************/
const int SIZE= 200009;
 
char str[SIZE]={0};
int check[SIZE]={0};
vector<vector<int>> ans;
set<int> s0,s1;
 
int main(){
    scanf("%s",str+1);
    int len=strlen(str+1);
 
    for(int i=1 ; i<=len ; i++){
        if(str[i]=='0') s0.insert(i);
        else s1.insert(i);
    }
 
    int possible=1;
    while(!s0.empty()){
        vector<int> tmp;
        char find='0';
        int last=0;
        
        while(1){
            if(s0.size()==0 && s1.size()==0break;
            if(s0.size()==0 && s1.size()>0){possible=-1break;}
 
            if(find=='0'){
                auto cur=s0.lower_bound(last);
                if(cur==s0.end()) break;
                tmp.push_back(*cur);
                last=*cur;
                find='1';
                s0.erase(cur);
            }
            else if(find=='1'){
                auto cur=s1.lower_bound(last);
                if(cur==s1.end()) break;
                tmp.push_back(*cur);
                last=*cur;
                find='0';
                s1.erase(cur);
            }
        }
 
        if(str[tmp.back()]=='1') possible=-1;
        else if(tmp.size()>0) ans.push_back(tmp);
    }
    if(!s0.empty() || !s1.empty()) possible=-1;
    if(possible==-1){printf("-1\n"); return 0;}
 
    printf("%d\n",ans.size());
    for(int i=0 ; i<ans.size() ; i++){
        printf("%d ",ans[i].size());
        showAll(ans[i],SPACE);
        printf("\n");
    }
    return 0;
}
cs


'Problem Solving > Greedy' 카테고리의 다른 글

[CF 898D] Alarm Clock  (0) 2019.06.28
[Codeforces 1153C] Serval and Parenthesis Sequence  (0) 2019.05.26
[Codeforces 1036D] Vasya and Arrays  (0) 2019.04.24
[Codeforces 1066B] Heaters  (0) 2019.02.18
[Codeforces 1110B] Tape  (0) 2019.02.11
댓글