ツバサの備忘録

主に備忘録代わりに精進記録を載せていくつもりです。

Typical DP Contest K - ターゲット

問題
提出コード

解法

区間スケジューリングのように、区間の終わりの部分に注目すると、LISに帰着させることができます。
まず、中心座標はx軸上に存在しているので、それぞれの円について、中心座標xrがわかっているとき、円と軸が接する2点は、x-rx+rになります。
すると、このx-rからx+rを、一つの区間としてみることができます。i番目の円C_iに対するx_i - r_iL_ix_i + r_iR_iとします。
あるサイズのターゲットが存在するとき、もう一つサイズを増やすには、
今あるターゲットの中で最大の円C_iと、新しく加わる円C_jが次のような関係になっている必要があります。
L_j \lt L_iかつR_i \lt R_j
図で表すとこのような状態です。 f:id:emtubasa:20190101125255p:plain
さて、ここで区間スケジューリングのように、区間の終わり、つまりR側に注目すると、Rを降順でソートすることで、円をいくつか選び、その円でサイズKのターゲットが作成できたとき、K個を大きさ順に並べると、上のソートした順番と同じになります。
ので、Rについて降順でソートしておけば、あとはLについてのみ考慮すれば、前から順番に円を選んでいくだけでターゲットが作成できるということです。
としたいのですが、コーナーケースが存在します。R_i = R_jとなるようなケースになります。このような場合は、Lについて昇順になっていると、L_iL_jのみでターゲットのサイズを増やせるかどうかの判定ができないので、降順にならべておけばよいです。

ここで、LISを思い出すことができれば、
 dp[K] = サイズKのターゲットを作成できるとき、その中で最小の円c_iについてのL_iの最小値
とすると、この問題を解くことができます。
c_jを合わせてサイズK+1のターゲットを作成するときに必要な条件が、L_i \lt L_jであるので、L_iはできるだけ小さくしておきたいからです。
dp[K]の中の要素は昇順に並んでいますので、c_iについて見ているとき、L_iのlower_boundを探しその部分を更新していき、なければ今最大のKに1追加した場所、つまりdp[K+1]L_iを格納する、という操作を行えばよいです。これをN回繰り返すと、値が格納されているKのうち最大の値が答えになります。