目次

AtCoder Regular Contest 175 A,C,D,E問題メモ

AtCoder Regular Contest 175

一見道筋が見えそうで、実装してから見落としや考察不足に気付く部分が多かった。

A - Spoon Taking Problem

A - Spoon Taking Problem

問題

解法

全員がスプーンを取れるケースは、「全員が自分の左側を取った」「全員が自分の右側を取った」以外にあり得ない。

全員が左を取ることになるような $T$ の個数を考えるとする。(右の場合も同様に考えられる)

各人の行動を $P$ の順にシミュレートして、

よって、「自分の番で、右側のスプーンが取られ左側のみ残っている、$S_i=?$ であるような人数」を $k$ として、$2^k$ 通りある。

全員が右を取る場合もシミュレートして、合計が答え。

Python3

C - Jumping Through Intervals

C - Jumping Through Intervals

問題

解法

やりたいことは分かるが、どう実装するかが難しい。

まず、無駄に値をふらふら上下させると2項間の差が増えてしまう。
$(L,R)$ の制約によって上下させる必要は生じるのだが、“最低限の上下回数”に抑えたい。

山と谷を列挙する。
ここでの山と谷とは、ざっくりイメージだが、 「山の $L_i$ と谷の $R_j$ を交互に結び、間を $R_j$ 以上 $L_i$ 以下で適切に埋めたのが、答えとなる」ような位置を指す。

i  0  1  2  3  4  5  6  7  8    ※それぞれのiに対し下がLi,上がRi
         9               
   8     |     8         
   |  7  |     |           7
   |  |  6     |     6  6  |
   |  |     5  |     |  |  |
   |  |     |  4     |  4  |
   3  |     3        |     3
      2           2  |
                  1  1
        山       谷    山
        
   6  6  6  4  4  2  2  4  4    この例の場合の答え

山と谷の間の埋め方は、2項間の差の総和に影響を与えずに辞書順最小にする必要があるので、

で埋めることになる。要は、単調増加/減少になる中で、なるべく小さい値を用いるとよい。

ただし最初と最後は、2項間の差の最小化のため、同じ値を連続させる。

山と谷の求め方

先頭から逐次見ていく中で、$(L_i,R_i)$ の範囲に共通部分があるものを、「区間」とする。

i  0  1  2  3  4  5  6  7  8    ※それぞれのiに対し下がLi,上がRi
         9               
   8     |     8         
   |  7  |     |           7
   |  |  6     |     6  6  |
   |  |     5  |     |  |  |
   |  |     |  4     |  4  |
   3  |     3        |     3
      2           2  |
                  1  1
  |-------||----||----||----| 区間
    [6,7]   [4,5] [1,2] [4,6] 区間の共通部分の [最小, 最大]

$i$ を進めるたびに、区間の共通部分は狭まっていく。($i=0,1,2$ と進めると、[3,8]→[3,7]→[6,7] となる)
これが、ある $i$ で $(L_i,R_i)$ と共通部分がなくなったら、そこで区切り、$i$ から新たな区間を始める。

このように区間を決めると、隣り合う区間の[最小,最大]は共通部分を持たない。
よって、今の区間が、前後の区間と比べて範囲的に小さいか、大きいかが決まる。([6,7] > [4,5] など)

この時、

同じ値が含まれている場合はどこでもよい。

また、両端の2区間には必ず山 or 谷が含まれる。(唯一の隣接する区間との大小関係により決まる)

山,谷のindexを列挙し、その間を適切に埋めれば、$A$ が求まる。

Python3

解法2

もっとシンプルに解ける。前から以下のように貪欲に決めていく。なるべく2項間の差を小さくしようとしている。

後ろからも同様に構成すると、2つのAnsのminを取ったものが、ほぼ答えとなる。

ただし、「全てに同じ値を置けるパターン」の場合はそれが答え。

またそうで無い場合でも、先頭と末尾に対して、2項間の差を最小化するためにちょっと調整の必要がある。

Python3

D - LIS on Tree 2

D - LIS on Tree 2

問題

解法

上限と下限

頂点1を根とした各頂点の深さを $d_i$ とする($d_1=1$)。

根から昇順に整数を割り当てることで、 全ての頂点で $L_i=数列長=d_i$ という状態になり、$\sum d_i$ が実現できる。これが上限となる。

逆に降順に割り当てると、全ての頂点で $L_i=1$ になり、$N$ が下限となる。

まずこの範囲に $K$ が無ければアウト。

ある場合は、ちょうど $K$ にできるか? どうすればできるか? を考える。
結論から言うと、範囲内であれば必ず $K$ にできる。

$K$ に調整する

昇順に割り当てた場合から $X=\sum d_i-K$ だけ、LIS長の総和を減らせればよい。

試しに、1つだけひっくり返してみると、

  ①       ②
  |       |
  ②  →   ①
  /\       /\
 ③④     ③④
   |       |
   ⑤       ⑤

(ひっくり返す前の)②の部分木に含まれる頂点のLISが、1ずつ減る。
上例の場合は、総計で4減ることになる。

つまり、総計で「ひっくり返した箇所の部分木の頂点数」だけ減るので、 この合計が $X$ になるようにひっくり返す箇所を決めれば、調整できそう。

ただ、「ひっくり返す」という考え方だと、複数箇所を考える際にちょっと考えづらい(連鎖的にひっくり返す場合など)。

より適切には、「LISを伸ばすのに使われる頂点と、使われない頂点」に分ける、と考える。

根は必ず伸ばすのに使われるとして、その他を以下のように決めると、

  ○       ③    ○: 伸ばすのに使われる
  |       |    ●: 使われない
  ●  →   ②
  /\       /\
 ○●     ④①
   |       |
   ○       ⑤

○の時のみ、ちゃんと伸ばすのに使われていることがわかる。
また、●の部分木の頂点数の合計だけ、LIS長の総和は減少する。

よって、「頂点を上手く選ぶと、その部分木の頂点数の合計を $X$ にできるか?」の部分和問題となる。

ただ、$N=2 \times 10^5$、$K=10^{11}$ サイズの部分和問題は、普通では無理。
しかし今回のように「部分木の頂点数」という制約があると、 「頂点数が大きい方から、採用できるなら貪欲に採用する」ことで、必ず作れることが証明できるらしい。

証明

●にする頂点が決まったら、あとは昇順/降順に置いていけば、答えとなる。

Python3

E - Three View Drawing

E - Three View Drawing

問題

解法

$K$ の上限が $N^2$ となっている。2次元に投影する以上、確かにそれが自明な上限である。

制約の範囲内で必ず構築できるらしいので、$K=N^2$ を実現する方法をまず考えてみる。
$K=N^2$ の場合、投影図は $N^2$ の正方形に決まっているので、影の一致は特に気にする必要は無い。

$xy$ 平面の $N \times N$ グリッドに、z座標を表す $0~N-1$ の数を置いていくことを考える。
この時、同じ行・列に同じ数を置いたら隠れることになってしまうので、数独のように、行・列内は全て別々の数字を置く必要がある。

y
 3| 0 3 2 1
 2| 1 0 3 2
 1| 2 1 0 3
 0| 3 2 1 0
 -|---------→ x
    0 1 2 3

逆にそれを満たせば、ひとまず投影して隠れないようにはできるので、$K=N^2$ の場合は成立する。

$K \lt N^2$ の場合は、この $(x,y,z)$ の集合から $K$ 個採用することで構築することを考える。
ただ、適当に採用すると、影が一致しなくなってしまう。

$K=N^2$ を成立させる配置の中でも、(感覚的にではあるが)考えやすそうな配置をベースに考えたい。

冒頭の例を可視化すると($N=4$ と $N=10$ の違いはあるが、考え方は同じとして)下のようになる。

この配置は3軸に対して対称的なので、yz、zx 平面に投影してみても、xy と全く同じ配置の表になる。

z                  x
 3| 0 3 2 1         3| 0 3 2 1
 2| 1 0 3 2         2| 1 0 3 2      2つともxyと全く同じ
 1| 2 1 0 3         1| 2 1 0 3
 0| 3 2 1 0         0| 3 2 1 0
 -|---------→ y    -+---------→ z
    0 1 2 3            0 1 2 3

試しに、この法則による配置をベースとして考察を進めてみる。

これでできる $(x,y,z)$ の組を、$N$ を変えて観察してみると、

できることが分かる。

①は、これ単独で採用することができる。どの投影図でも、同じ箇所に影ができる。

②と③は、1グループ3つセットで採用することができる。3個セットで、どの投影図でも同じ3箇所に影ができる。

また、特に②は、この代わりに $(0,0,3),(0,3,0),(3,0,0)→(0,0,0)$ のように、①相当に置き換えることができる。
これで、3つ単位でなく、1個単位でも採用できることになり、自由度が増す。

①+②は必ず $N$ 個(グループ)ある。$N \ge 2$ では $K$ を3で割った端数を必ず調整できる($N=1$ は自明)。

③→②を3個単位→②を1個単位→① の順に貪欲に使っていくと、構築できる。

ただし、

y
 5| 1 0 5 4 3 2
 4| 2 1 0 5 4 3
 3| 3 2 1 0 5 4
 2| 4 3 2 1 0 5
 1| 5 4 3 2 1 0
 0| 0 5 4 3 2 1
 -|------------→ x
    0 1 2 3 4 5

こうすると、足りるようになる。

Python3