2019年8月8日木曜日

ARC 083 E - Bichrome Tree

ARC 083 E - Bichrome Tree

頂点vvが与えられたとき、vvの部分木でvvと同じ色の重みの和はXvX_vと決まっているが、もう一方の色の重みの和については割り当て次第である程度動かせるはず。そして、この重みの和は、小さい分には先祖の重みの割り当て方が増えるだけなので、小さければ小さいほど良いはず。

そこで、f(v)f(v)を次のように定める: 部分木vvで、vvと同じ色の重みの和がXvX_vになるように重みを割り当てたときの、もう一方の色の重みの和の最小値。

ffの漸化式について考える。頂点vvの子をc1,...,ckc_1, ..., c_kとする。部分木cic_iの重みの和は、一方の色がXciX_{c_i}、もう一方の色が少なくともf(ci)f(c_i)である。つまり、kk個の部分木の重みの決め方は

Xc1X_{c_1} Xc2X_{c_2} XckX_{c_k}
f(c1)f(c_1) f(c2)f(c_2) f(ck)f(c_k)

から上下の2択がkk個あるので2k2^k通り考えられて、一方の色の重みの和をXvX_v以下にするという条件でもう一方の色の重みの和を最小にできれば、その値がf(v)f(v)である。これはナップサック問題のようなDPで求まる: gv(y,z)g_v(y, z)を、部分木c1,...,cyc_1, ..., c_yの一方の色の重みの和がzz以下であるという条件下でのもう一方の色の重みの和の最小値とする。このとき、f(v)=gv(k,Xv)f(v) = g_v(k, X_v)である。gvg_vの漸化式は次のように書ける:

gv(0,z)=0g_v(0, z) = 0

gv(y,z)=min(gv(y1,zXy)+f(y),gv(y1,zf(y))+Xy,+)g_v(y, z) = \min(g_v(y-1, z-X_y)+f(y), \: g_v(y-1, z-f(y))+X_y, \:+\infty)

途中でf(v)=+f(v) = +\inftyとなったら答えはIMPOSSIBLEである。(ただし、それぞれzXy0,zf(y)0z - X_y \ge 0, z-f(y) \ge 0でない場合は除いて計算する。また、vvが子を持たない場合はf(v)=0f(v) = 0だが、この計算式のままでも自然にf(v)=gv(0,Xv)=0f(v) = g_v(0, X_v) = 0となるので特別扱いしなくても書ける。)

計算量について。木のそれぞれの頂点vvについてDPすることになり、その計算量はO(vXv){\mathcal O}(vの子の数 \cdot X_v)である。したがって、全体ではO(NmaxiXi){\mathcal O}(N\max_i X_i)

2019年8月7日水曜日

yukicoder No.269 見栄っ張りの募金活動

yukicoder No.269 見栄っ張りの募金活動

最初にSSから0+K+...+(N1)K=N(N1)K/20+K+...+(N-1)K = N(N-1)K/2を引いておくと、1つ前の生徒の金額以上に寄付をするという問題に変わる。定式化すると、総和がSN(N1)K/2S-N(N-1)K/2になるような長さNNの数列で、単調非減少であるものを数え上げればよいことになる。これは分割数、つまり非負整数SN(N1)K/2S-N(N-1)K/2NN個の非負整数に分割する方法を数え上げることに等しい。1 O(SN){\mathcal O}(SN)


  1. S<N(N1)K/2S < N(N-1)K/2の場合の答えは00である。 ↩︎

JAG Spring Contest 2014 C - Decoding Ancient Messages

JAG Spring Contest 2014 C - Decoding Ancient Messages

行と列の間の(辞書式順序に関する)最大重みマッチングを与えればよい……のだが、辞書式順序を単に整数にコーディングすればよいという部分を思いつけなくてけっきょく解説を見た。行・列は高々50でアルファベットは52種類なので、各辺の重みを

  • A: 515251^{52}
  • B: 515151^{51}
  • z: 51051^0

とすれば、「BがどれだけあってもAが1個あるほうが価値が高い」という辞書式の重みを実現できる。

2019年8月5日月曜日

ABC 136 F - Enclosed Points

ABC 136 F - Enclosed Points

各点iSi \in Sについて、iiが何回数えられるかを求めればよいので、包除を考えるのがよさそう。点iiの上下左右の領域にある点の集合L,R,D,USL, R, D, U \in Sを定める:

L(i):={(x,y)Sx<xi}R(i):={(x,y)Sxi<x}D(i):={(x,y)Sy<yi}U(i):={(x,y)Syi<y}L(i) := \{(x, y) \in S| x<x_i\} \\ R(i) := \{(x, y) \in S| x_i < x\} \\ D(i) := \{(x, y) \in S | y<y_i\} \\ U(i) := \{(x, y) \in S| y_i < y\}

iiを含むSSの部分集合の総数は

2N2L(i)2R(i)2D(i)2U(i)+2L(i)U(i)+2L(i)D(i)+2R(i)U(i)+2R(i)D(i)12^N - 2^{|L(i)|}-2^{|R(i)|}-2^{|D(i)|}-2^{|U(i)|} \\ +2^{|L(i) \cap U(i)|}+2^{|L(i) \cap D(i)|}+2^{|R(i) \cap U(i)|}+2^{|R(i) \cap D(i)|}-1

で求まるので、これをiSi \in Sについて足し合わせればよい。1

さて、L(i),R(i),D(i),U(i)|L(i)|, |R(i)|, |D(i)|, |U(i)|は点をxx座標やyy座標についてソートしておけば尺取り法や二分探索等でそれぞれ求まる……が、よく見るとxixj,yiyj(ij)x_i \neq x_j, y_i \neq y_j (i \neq j)という条件があるので、単に整数0,1,...,N10, 1, ..., N-1が1回ずつ現れるだけであった。したがって、

iS(2N12L(i)2R(i)2D(i)2U(i))=N(2N1)4(20+21+...+2N1)=(N4)(2N1)\begin{aligned} & \sum_{i \in S}\bigl(2^N-1 - 2^{|L(i)|}-2^{|R(i)|}-2^{|D(i)|}-2^{|U(i)|} \bigr) \\ & = N \cdot (2^N-1) - 4 \cdot (2^0 + 2^1 + ... + 2^{N-1}) \\ & = (N-4)(2^N-1) \end{aligned}

である。

次にL(i)D(i),L(i)U(i),R(i)D(i),R(i)U(i)|L(i) \cap D(i)|, |L(i) \cap U(i)|, |R(i) \cap D(i)|, |R(i) \cap U(i)|を求める。(xi,yi)i{1,...,N}(x_i, y_i)_{i \in \{1, ..., N\}}xx座標についてソート済み(x1x2...xNx_1 \le x_2 \le ... \le x_N)とする。順序付きの集合OOを用意して、y1,y2,...,yNy_1, y_2, ..., y_Nの順にOOに入れていく時、点iiを処理した時点でOOの中のyiy_i未満の点の総数はL(i)D(i)|L(i) \cap D(i)|に等しく、yiy_iより大きい点の総数はL(i)U(i)|L(i) \cap U(i)|に等しい。同様のことを逆順yN,yN1,...,y1y_N, y_{N-1}, ..., y_1でやればR(i)D(i),R(i)U(i)|R(i) \cap D(i)|, |R(i) \cap U(i)|が求まる。


2Dのクエリを処理できるデータ構造があればテクニックが無くてもできそう。2Dセグメント木とかウェーブレット行列とかいろいろあるようだが、このスライドを眺めていて、とりあえずrange treeがすぐに書けそうに見えたので書いた。かなり重いが一応通った。

fractional cascadingでオーダーを落とすやつも書いた


  1. 最後の1-1は空集合を除いている。 ↩︎