kurarrr's memooo

主に競プロ備忘録

みんプロ2017 B - チーム決め

問題概要

{a_i} (1 <= i <= N), {b_i} (1 <= i <= M)が与えられる.
各数列からK個選んで,昇順に並べた時のmax_(1 <= i <= K) (abs(a_i - b_i))を最小化せよ.
1 <= N,M,K <= 105, 1 <= a_i,b_i <= 109

解法

二分探索する. l = -1としないと X = 0とできる時に引っかかるので注意.
各探索では a[i] に対して a[i]-X <= b[j] <= a[i]+X を満たす最小のb[j]を貪欲に選んでいけば良い.
尺取り法を使えば O((N+M)log109)

メモ

二分探索 -> 貪欲で選ぶと嘘っぽい?(嘘じゃない)
-> BITで数えられるやん! -> MLEするわ...

絶対値の差がX以下のペアを選んで行く時,a[i]に対して条件を満たす最小のb[j]があり,
これ以外のb[j'] (昇順なのでj'>j)を選ぶとより多くのペアが作れると仮定する.
すると
b[j] を他の a[i'] (i'>i) に割り当てる -> 交差するので絶対値の差は大きくなる. a[i]-b[j],a[i']-b[j']の方が良い.
b[j] を割り当てない -> 単にa[i'] (i'>i)の選択肢が減るのでa[i]-b[j]の方が良い.
冷静に考えてみると明らか. 頭固い.

コード

#include "bits/stdc++.h"

#define ALL(g) (g).begin(),(g).end()
#define REP(i, x, n) for(int i = x; i < n; i++)
#define rep(i,n) REP(i,0,n)
#define RREP(i, x, n) for(int i = x; i >= n; i--)
#define rrep(i, n) RREP(i,n,0)
#define pb push_back

using namespace std;

using ll = long long;
using P = pair<int,int>;
using Pl = pair<ll,int>;

const int mod=1e9+7,INF=1<<30;
const double EPS=1e-12,PI=3.1415926535897932384626;
const ll lmod = 1e9+7,LINF=1LL<<60;
const int MAX_N = 100005;

int a[MAX_N],b[MAX_N];

int main(){
  int N,M,K; cin >> N >> M >> K;
  rep(i,N) scanf("%d",a+i);
  rep(i,M) scanf("%d",b+i);
  sort(a,a+N);
  sort(b,b+M);
  int l = -1, r = 1e9, mid;
  while(abs(r-l)>1){
    mid = (l+r)/2;
    int cnt = 0;
    for(int i=0,j=0;i<N&&j<M;i++){
      int lb = a[i] - mid, ub = a[i] + mid;
      while(j<M&&b[j]<lb) j++;
      if(b[j]<=ub) cnt++,j++;
    }
    if(cnt>=K) r = mid;
    else l = mid;
  }
  cout << r << endl;
  return 0;
}