Official

C - 集合場所の決定 / Deciding the Meeting Place Editorial by physics0523


\(A_1 \le A_2 \le \dots \le A_N\) となるようソートしたとして以降の議論を行います。

まず、全員が集合できるかどうかを判定します。
もし、障害物が \(A_1\) 以上 \(A_N\) 以下の座標に存在すれば両端の人が出会えないため全員が集合できません。
逆に、障害物が \(A_1\) 以上 \(A_N\) 以下の座標に存在しなければこの間のどの座標でも全員が集合できます。

全員が集合できる場合、集合場所 \(T\) を定めて \(\sum |A_i-T|\) を最小化するためには、 \(m=\lceil N/2 \rceil\) として座標 \(A_m\) に集まるのが最適であることが知られています。

略証:

  • もし \(A_m\) 未満の座標 \(x\) に集合した場合、座標 \(x+1\) に集合するとして損しません。
    • どちらの座標でも集合場所より大きな座標から来る人が小さな座標から来る人以上に存在します。それならより大きな座標で集合した方が移動距離の総和を最小化できます。
  • 同様の議論で、もし \(A_m\) 超過の座標 \(y\) に集合した場合、座標 \(y-1\) に集合するとして損しません。

なので、答えとして \(\sum |A_i - A_m|\) を出力すればこの問題に正解できます。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

int main(){
  ll N,M;
  cin >> N >> M;
  vector<ll> A(N),B(M);
  for(auto &nx : A){cin >> nx;}
  sort(A.begin(),A.end());
  bool bad=false;
  for(auto &nx : B){
    cin >> nx;
    if(A[0]<=nx && nx<=A[N-1]){bad=true;}
  }
  if(bad){cout << "-1\n"; return 0;}
  ll res=0;
  for(ll i=0;i<N;i++){
    res+=abs(A[i]-A[N/2]);
  }
  cout << res << "\n";
  return 0;
}

posted:
last update: