BOJ 1467 - 수 지우기

image.png

원래 수가 $S$이고 지워야할 수들의 집합이 $T$라고 하자.

최종 정답의 길이는 $n(S)-n(T)$ 이다.

정답에 첫 번째 올 숫자를 생각해보자.

$9 \to 0$ 으로 훑자. 각 숫자들의 인덱스를 미리 구해둔다.

$9$에서 가장 먼저 나오는 위치가 $i$라고 하자. 그 뒤에 나오는 위치인 $j~(i < j)$를 생각했을 때,

$i$가 정답에 추가되어야할 현재 수가 될 수 있다는 것은 정답에 마지막에 추가된 숫자의 $S$에서의 위치가 $i'$ 일 때, $i' < k < i$ 의 위치의 수들을 모두 지울 수 있어야 한다는 의미이다.

또한 $S_j$ 가 이번 숫자로 올 수 있다면 항상 $S_i$ 도 올 수 있으므로 각 숫자마다 현재 가장 처음에 있는 인덱스를 봐야한다.

어쨌든 $i$가 올 수 있다면, $S_i$ 를 정답에 추가하고 $i' < k < i$ 인 $k$에 대해 모두 지워준다.

$9 \to 0$ 까지 훑었는데 아무 숫자도 추가하지 못했다면 그냥 마지막 추가된 위치 + 1의 숫자를 추가해주면 된다.

void solve() {  
   int n;  
   string s, t;  
   cin >> s >> t;  
   n = sz(s);  
   vi remove_cnt(10);  
   vector<deque<int>> digit_idx(10);  
   for (char c: t) remove_cnt[c - '0']++;  
   for (int i = 0; i < n; i++) digit_idx[s[i] - '0'].pb(i);  
  
   int nxt_add_idx = 0;  
  
   string ans;  
   auto insert = [&](int i) {  
      ans += s[i];  
      for (int d = 0; d < 10; d++) {  
         while (sz(digit_idx[d]) && digit_idx[d][0] <= i) digit_idx[d].pop_front();  
      }  
      for (int j = nxt_add_idx; j < i; j++) remove_cnt[s[j] - '0']--;  
      nxt_add_idx = i + 1;  
   };  
  
   for (int l = 0; l < n - sz(t); l++) {  
      for (int d = 9; d >= 0; d--) {  
         if (sz(digit_idx[d]) && sz(digit_idx[d]) == remove_cnt[d]) {  
            continue;  
         }  
         if (!sz(digit_idx[d])) continue;  
         vi cnt(10);  
         int can_remove = 1;  
         for (int j = nxt_add_idx; j < digit_idx[d][0]; j++) {  
            cnt[s[j] - '0']++;  
            if (cnt[s[j] - '0'] > remove_cnt[s[j] - '0']) {  
               can_remove = 0;  
               break;  
            }  
         }  
         if (can_remove) {  
            insert(digit_idx[d][0]);  
            break;  
         }  
      }  
      if (sz(ans) != l + 1) insert(nxt_add_idx);  
   }  
   cout << ans;  
}

Tags:

Categories:

Updated:

Comments