目次

AtCoder Beginner Contest 187 D,E,F問題メモ

AtCoder Beginner Contest 187

PC新調したら移行作業で正月がつぶれた。

いろんなアプリに依存してると、こういう時に苦労するね。(データ移行がきちんと考えられているアプリばかりではないので)

D - Choose Me

D - Choose Me

問題

解法

何もしない $B$ 派にはなるべく投票に行って欲しいし、そのままでは $A$ 氏に投票してしまう $A$ 派にはなるべく寝返って欲しい。

増やしたい指標が2つあるのを、上手く考えて統合する。

得票数の差分($B-A$)に注目すると、

なので、$2A_i+B_i$ の大きい順に演説するのが得で、その累積和が $\displaystyle \sum_iA_i$ を超えるまで回る必要があるとわかる。

Python3

E - Through Path

E - Through Path

問題

解法

木なので、辺の一方の頂点から、もう一方を通らずに移動できる頂点は、部分木となる。

○--○--○--,      ,--○
        ○--A----B--○

クエリ毎に部分木全てに $x_i$ を足していると時間がかかるので、AやBに「この下には全部 $x_i$ が足されますよー」という情報を記録しておいて最後に復元すれば、全体を辿るのは1発で済む。

    ○
   /  \
  A  ○    B以下の部分木に足す場合、Bにのみ「xi」足されたことを記録しておいて、
  /\   \    最後に根から集計する
 B○  ○
 /\
●●

根は適当な1頂点を決めればよいが、その場合、AとBの位置関係によっては足したい範囲を1つの部分木で表現できない場合もある。

    ●
   /  \
  A  ●    A以下の部分木に足したい……
  /\   \    Aに記録しても根から辿ったときに反映できない……
 B●  ●
 /\
○○

その場合、いったん、全体に $x_i$ 足してしまう。
その上でB以下の部分木にそれを打ち消すように「$-x_i$」足すと考えればよい。

これで「部分木以下全ての頂点に加算」という1つの操作だけにクエリを分解でき、根からの集計が可能になった。

各クエリで、上記どちらの方法を採るかを決めるのに、辺のどちらの頂点が根に近いかを判別する必要がある。
まず最初に根から探索して各頂点の深さなり、親なりを計算しておくと、判別できる。

Python3

F - Close Group

F - Close Group

問題

解法

制約がbit演算を物語る。

頂点集合をbitで管理する。全ての集合の組合せの数は多くとも $2^{18}=262144$ で、線形な計算が可能。

             76543210
{1,2,4,5} → 00110110 = 54

その上で、以下を事前計算しておく。

次に以下のDPをする。

'1,10,100,…' については自明に1となる。

遷移は、以下のように考えられる。

S = 1101101

これを2グループに分ける分け方を全探索する

1001001  このように分けたとする
0100100

1001001  を1つの連結成分に出来るか? を cmp より取得
  できないなら次へ
  できるなら、そう分けたときの答えは DP[0100100] + 1

全分け方について調べ、その中での最小値が、DP[S] となる

最終的に $DP[111 ... 1]$ が答え。

このように、「$N$ 個のbitの集合 $2^N$ 個をイテレートしながら、更にその内部で部分集合をイテレートする」操作は、計算量 $O(3^N)$ となる。
「最初のbit集合に選ばれない」「最初のbit集合には選ばれたが、部分集合には選ばれない」「部分集合にも選ばれる」の3通りを、各bitが独立に持つと考えればよい。

あるbitの部分集合をイテレートする方法は、以下参照

Python3

解法2

この問題設定自体、最小クリーク被覆問題 と名前が付いているらしい。

それによると、補グラフ(元のグラフから各頂点間の辺の有無を反転させたグラフ)を考えると、彩色問題に帰結できる。

彩色問題は、グラフ上で直接辺で繋がった2頂点は別の色で塗る、というルールで、$k$ 色で矛盾無く塗れますか or 何色あれば塗れますか、という問題。

「補グラフで辺がある2頂点は別の色」なので、「同じ色の2頂点なら元のグラフで辺がある」ことがいえる。

彩色可能な最小色数を求めればよい。

詳細なアルゴリズムは未調査だが、これは $O(2^NN)$ でできるらしい。