2019年7月30日火曜日

ARC 016 C - ソーシャルゲーム

ARC 016 C - ソーシャルゲーム

既に持っているアイドルの集合S{1,...,N}S \subseteq \{1, ..., N\}が与えられたとき、そこからアイドルをコンプリートするのに必要な金額の期待値をf(S)f(S)としてDPする。

くじjjを引いた時にアイドルiiが出る確率をpj,ip'_{j, i}とする。くじが1つしかない場合は

f(S)=cost1+i{1,...,N}f(S{i})p1,i=cost1+iSf(S{i})p1,i+iSf(S)p1,i\begin{aligned} f(S) & = cost_1 + \sum_{i \in\{1, ..., N\}} f(S \cup \{i\})p'_{1,i}\\ & = cost_1 + \sum_{i \notin S} f(S \cup \{i\})p'_{1,i} + \sum_{i \in S}f(S)p'_{1,i} \end{aligned}
が成り立つから、f(S)f(S)について解くと
f(S)=(cost1+iSf(S{i})p1,i))(1iSp1,i)1()f(S) = \bigl( cost_1 + \sum_{i \notin S} f(S \cup \{i\})p'_{1,i} )\bigr) \bigl(1- \sum_{i \in S}p'_{1,i}\bigr)^{-1} \qquad (*)

である。しかし、くじが複数の場合は

f(S)=minj(costj+iSf(S{i})pj,i+iSf(S)pj,i)f(S) = \min_j \Bigl( cost_j + \sum_{i \notin S} f(S \cup \{i\})p'_{j,i} + \sum_{i \in S}f(S)p'_{j,i} \Bigr)

となって、これは単純には解けないように見える……が、よく考えると最適な引き方はSSのみによって決まるのだから、状態SSの時にありえる引き方は、新しいアイドルが出るまでくじ11を引き続ける・くじ22を引き続ける・…・くじMMを引き続けるのMM通りである。そこで、手持ちのアイドルがSSの場合にくじjjを引き、それ以外は最適な引き方をする時の期待金額をfjf_jで表すと、f(S)=minjfj(S)f(S) = \min_jf_j(S)である。fjf_jの漸化式も上と同様に書けて

fj(S)=costj+iSfj(S{i})pj,i+iSfj(S)pj,i=costj+iSf(S{i})pj,i+iSfj(S)pj,i\begin{aligned} f_j(S) & = cost_j + \sum_{i \notin S} f_j(S \cup \{i\})p'_{j,i} + \sum_{i \in S}f_j(S)p'_{j,i} \\ & = cost_j + \sum_{i \notin S} f(S \cup \{i\})p'_{j,i} + \sum_{i \in S}f_j(S)p'_{j,i} \end{aligned}

(二行目はSSfj(S)=f(S)S \subsetneq S' \Rightarrow f_j(S') = f(S')から従う。SSに含まれているアイドルをすべて持っていてSSではない状態に対してはfjf_jffは同一である。) 同様にfj(S)f_j(S)について整理すると()(*)とまったく同じ式になり、最終的な漸化式は

f(S)=minjfj(S)=minj((costj+iSf(S{i})pj,i))(1iSpj,i)1)\begin{aligned} f(S) & = \min_j f_j(S) \\ & = \min_j \Bigl(\bigl( cost_j + \sum_{i \notin S} f(S \cup \{i\})p'_{j,i} )\bigr) \bigl(1- \sum_{i \in S}p'_{j,i}\bigr)^{-1}\Bigr) \end{aligned}

となる。


http://kyopro.hateblo.jp/entry/2019/07/15/013501
sdfi13jfxさんの記事がいちばん参考になった。

2019年7月25日木曜日

UTPC 2013 F - 魔法の糸

UTPC 2013 F - 魔法の糸

解説を見てACしたのだが、実装でつまづいた……というか、計算量がよくわかっていなかったのでメモ。

頂点ppを含む連結成分V(p)V(p)と頂点qqを含む連結成分V(q)V(q)を併合するとき、V(p)V(p)V(q)V(q)の間の辺をどう集めるかが問題になるが、重みを隣接行列にでも記録しておいて、単にV(p)V(p)の頂点とV(q)V(q)の頂点のペアを総当たりすればよい。こうすると、この部分の計算量がQQ回の更新でO(N2Q){\mathcal O}(N^2Q)になってしまいそうな気がしていたのだが、よく見ると1つの頂点ペア{v,w}\{v, w\}につき高々1回しか処理されていないので、O(N2+Q){\mathcal O}(N^2+Q)で済んでいる。

全体の計算量について。Kruskal法の前に辺の長さでソートする部分がボトルネックになる。頂点pp, qqを結ぶii個目のクエリに対して、V(p),V(q)V(p), V(q)の間の辺がdid_i本あったとすると、上で述べたようにd1+...+dQMd_1+ ... + d_Q \le Mである。また、以前のクエリでV(p)V(p)の最小全域木を作ろうとした時に選んだ辺は高々V(p)|V(p)|であり、V(q)V(q)についても同様にV(q)|V(q)|である。V(p)+V(q)N|V(p)|+|V(q)| \le Nだから、ii個目のクエリで扱うべき辺の数は高々N+diN+d_i本となる。したがって、QQ回のソートの計算量は

O(i=1Q(N+di)log(N+di))=O(i=1Q(N+di)logN)=O(i=1QNlogN+i=1QdilogN)O(QNlogN+MlogN)O((N2+M)logN).\begin{aligned} & {\mathcal O} \bigl (\sum_{i=1}^Q(N+d_i)\log(N+d_i) \bigr) \\ = & \: {\mathcal O} \bigl (\sum_{i=1}^Q(N+d_i)\log N \bigr) \\ = & \: {\mathcal O} \bigl (\sum_{i=1}^Q N \log N + \sum_{i=1}^Q d_i \log N\bigr) \\ \subseteq & \: {\mathcal O} \bigl (QN \log N + M \log N\bigr) \\ \subseteq & \: {\mathcal O} \bigl ((N^2 + M) \log N\bigr). \end{aligned}

ソートの部分はバケットソートでも通って計算量はO(N2+M+Qmaxwi){\mathcal O}(N^2+M+Q\max w_i)となる……けど、別に速くはならない。