BOJ 25406 - 식사 계획 세우기

image.png

이게 뭔문젠가 하고 초장부터 문제 잘못읽어서 꼬였다.

두 개의 set이나 priority queue를 관리한다.

  • 하나는 현재 남은 수 들 중 가장 많은 원소의 개수와 그 숫자를 바로 얻어올 수 있게 관리한다.
  • 하나는 현재 남은 수들 중 가장 빠른 인덱스에 위치한 수와 그 인덱스를 얻어올 수 있도록 관리한다.

채워야 할 배열이 길이 $n$ 이 남았을 때, $\left\lfloor \dfrac {n+1}2 \right\rfloor+1$ 개 이상이라면 최대한 그리디하게 배치해도 인접하는 수가 생기므로,

이것이 생기지 않도록 첫 번째 set에서 가장 큰 수가 이걸 처리해야 할 때라면 그때그때 처리해준다.

왜 그때그때 처리해줘도 되냐면 $\left\lfloor \dfrac {n+1}2 \right\rfloor$ 개라고 했을 때 이러한 개수를 가진 수가 남은 $n$ 개에서 두 개이상 존재함은 불가능하기 때문이다.

바로 처리해주어야 할 수가 없다면, 두 번째 set에서 가장 빨리 오는걸 골라준다.

만약 가장 빨리오는것이 이전에 썼던 수라면 그 다음 빨리 오는것을 골라주면 된다.

void fail() {  
   cout << -1;  
   exit(0);  
}  
int limit(int len) { return (len + 1) / 2; }  
  
void solve() {  
   int n;  
   cin >> n;  
   vi a(n), v;  
   fv(a);  
   v = a;  
   uniq(v);  
   for (int &i: a)i = lbi(v, i);  
   int V = sz(v);  
  
   vvi pos(V);  
   auto remain = [&](int i) { return sz(pos[i]); };  
   for (int i = n - 1; i >= 0; i--) pos[a[i]].pb(i);  
  
   auto cmp1 = [&](auto &a, auto &b) {  
      if (a.fi ^ b.fi) return a.fi > b.fi;  
      return a.se < b.se;  
   };  
   auto cmp2 = [&](auto a, auto b) {  
      if (a.fi ^ b.fi) return a.fi < b.fi;  
      return a.se < b.se;  
   };  
   set<pi, decltype(cmp1)> set1(cmp1);  
   set<pi, decltype(cmp2)> set2(cmp2);  
   for (int i = 0; i < V; i++) {  
      set1.insert({remain(i), i});  
      set2.insert({pos[i].back(), i});  
   }  
  
   vi ans;  
   for (int i = 0, last = -1; i < n; i++) {  
      // 이것보다 많으면 fail  
      debug(ans);  
      int remain_len = n - i;  
      int mx = limit(remain_len);  
  
      auto it1 = set1.begin();  
      auto it2 = set2.begin();  
      if (it1->fi > mx || (last != -1 && remain(last) > limit(remain_len - 1))) fail();  
  
      int nxt = -1;  
  
      if (it1->fi > limit(remain_len - 1)) {  
         nxt = it1->se;  
      } else {  
         nxt = it2->se;  
         if (nxt == last) {  
            it2++;  
            nxt = it2->se;  
         }  
      }  
      ans.pb(pos[nxt].back() + 1);  
      set1.erase({remain(nxt), nxt});  
      set2.erase({pos[nxt].back(), nxt});  
      pos[nxt].pop_back();  
      if (remain(nxt)) {  
         set1.insert({remain(nxt), nxt});  
         set2.insert({pos[nxt].back(), nxt});  
      }  
      last = nxt;  
   }  
   for (int i: ans) {  
      cout << i << ' ';  
   }  
}

Tags:

Categories:

Updated:

Comments