ABC294 - F

이분 탐색은 알았는데, 결정 함수를 짜는 방법을 모르겠어서 에디토리얼을 참고했다.

아이디어Permalink

우리가 정답인 농도를 이분탐색으로 구하는데, NMNM개의 조합 중, 현재 보고 있는 농도 xx보다 높은 것의 개수를 구한다.

그것이 kk 이상이라면 xx를 더 높여주고, 아니면 낮춰주면서 정답을 찾아낸다.

결정 함수Permalink

xx의 농도에 대해 NMNM개의 조합의 농도 중 몇개가 xx보다 작을까?

설탕물이 ss의 설탕과 tt의 물로 이루어져 있다고 하자.

이것이 xx가 되는 설탕의 양을 u=tx1xu=t \dfrac x{1-x} 로 정의한다.

실제로 그런것은 아니지만 물에 있는 설탕의 비율을 x1x\dfrac x{1-x} 로 두어도 문제없다.

농도는 100100 같은 상수를 제거하고 ratio만 따져도 충분하다.

이제 여기서 sus \ge u 라면 sus-u 그램의 설탕이 더 있다는 것이고

s<us < u 라면 usu-s 의 설탕이 부족하다는 것이다.

usu-s의 설탕이 부족하다는 것을 sus-u 만큼의 음의 설탕이 더 있다고 재정의함으로써, 우린 항상 sus-u 만큼의 설탕에 대해서만 다룰 수 있다.

매번 결정함수마다 다음과 같은 작업을 한다.

  • (v1,v2,,vM)(v_1,\,v_2, \dots , v_M) 을 Aoki가 가진 설탕물들에 대해서 (su)(s-u) 라고 하자.
  • vv 를 정렬한다.
  • Takahashi의 설탕물들을 다음과 같이 처리한다.
    • ww를 현재 설탕 물의 (su)(s-u)라고 하면, Aoki가 가진 것 중 viv_i 가 최소 w-w 이상이여야 xx이상의 농도가 나오므로 이분 탐색으로 개수를 찾아주면 된다.

코드Permalink

void solve() {  
   int n, m, k;  
   cin >> n >> m >> k;  
   vector<pi> ab(n), cd(m);  
   for (auto&[a, b]: ab) cin >> a >> b;  
   for (auto&[c, d]: cd) cin >> c >> d;  
  
   double L = 0, R = 1;  
   for (int i = 0; i < 100; i++) {  
      double M = L + (R - L) / 2;  
      int ge_cnt = 0;  
  
      double u = M / (1 - M);  
      vector<double> v(m);  
      for (int i = 0; i < m; i++)  
         v[i] = cd[i].fi - cd[i].se * u;  
      sort(all(v));  
  
      for (int j = 0; j < n; j++) {  
         double w = ab[j].fi - ab[j].se * u;  
         ge_cnt += m - lbi(v, -w);  
      }  
      (ge_cnt < k ? R : L) = M;  
   }  
   cout.precision(15);  
   cout << fixed << L * 100;  
}

후기Permalink

이 문제에서 놓쳤던 것은 결정 함수의 작성에서 xx 에 대해서 한 번의 결정함수마다 무언가 정렬을 새롭게 해줄 수 있다는 사실이다.

이런 테크닉은 처음 알았다.

아예 이분 탐색이 들어가기 전에 어떻게든 C,DC,D 배열을 먼저 정렬해두고 풀어야 된다는 생각이 있었고, 그것이 못 푼 원인이다.

Tags:

Categories:

Updated:

Comments