Loading [MathJax]/jax/output/CommonHTML/jax.js

目次

AtCoder Beginner Contest 223 F,G問題メモ

AtCoder Beginner Contest 223

F - Parenthesis Checking

F - Parenthesis Checking

問題

解法

区間加算更新・区間min取得の遅延評価セグメント木。
遅延セグ木はACL Libraryにあるが、更新操作と取得操作の演算が違ってもちゃんと使えますか、という練習問題かも。

正しい括弧列の判定は、'(' を +1')' を 1 に置きかえて、累積和を考えるのがよくある解法。

    0 1 2 3 4   Sのindex
--------------
S   ( ( ) ) ( 
A  0 1 2 1 0 1  累積和
--------------
   0 1 2 3 4 5  累積和のindex

文字列 S から [l,r) を取り出した部分文字列が正しい括弧列かどうかは、以下をともに満たすかで判定できる。

要は、開き括弧と閉じ括弧の数は等しいですか、途中で開かれた括弧より閉じた括弧の方が多くなっていませんか、ということを確認している。

区間minが必要になるので、Aをセグメント木で管理するなどで、'2'のクエリには答えることができる。

しかし、今回は'1'のクエリ、括弧を入れ替えるという操作が出てくる。
SlSr の入れ替えにより累積和がどう影響するかというと、

このようになるので、区間加算ができればよい。

A に対して区間更新と区間取得ができればよいので、遅延評価セグメント木で実装できる。

抽象化された遅延セグ木は5つの関数を定義するが、今回は以下のようになる。

関数 役割 今回の問題
e() dataの単位元 常に を返す関数
id() lazyの単位元 常に 0 を返す関数
op(a,b) data同士のマージ min
mapping(f,x) dataにlazyを反映 add
composition(f,g) lazy同士のマージ add

上の記事からリンクされてるチートシートに、そのものズバリな設定がある。親切。

Python3

G - Vertex Deletion

G - Vertex Deletion

問題

解法

ABCで2回連続全方位木DPが出たので、世は空前の全方位DPブーム。
(先週せっかくライブラリ化したのに、今回Fで延々とバグらせ続けていたせいで日の目を見ませんでした。悲しいね)

グラフ上から、「どの2辺も両端の頂点を共有しない」という条件で選んだ辺集合をマッチングと呼ぶ。
その中で、取れる辺数が最大であるものを最大マッチングと呼ぶ。

通常のグラフにおける最大マッチングは難しいが、二部グラフや木では効率的に解ける方法がある。
木の最大マッチングはいろいろな解き方があるが、葉から貪欲にマッチングしていく、という方法が可能。

      ○
    /  \
  ○     ○
 /|\    /\
○○○  ○○
          |
          ○
    ↓↓↓
      ○
    /  \
  ①     ③
 /|\    /\
①○○  ③②
          |
          ②

上の例の場合、最大マッチングは3だが、 根の頂点自身はペアに使われずとも各子の部分木だけで完結しているので、 消しても最大マッチングに影響ない。

      ②
    /  \
  ①     ②
 /|\
①○○

逆にこの例では最大マッチング達成のためには根頂点が必要で、消すことが出来ない。

従って、根を決めて、以下のような木DPを考えた場合、

DP[]c が最大マッチングと一致し、flag=1 なら根は消せる。0 なら消せないとなる。

なお、根の c は最大になるに決まっているので、答えを求める上では flag だけ管理すればよいが、 イメージ的にわかりやすくするため c を添えて考える。

DP[v] の値は、v の子頂点たちを先に計算しておくことで、以下で求められる。

全方位DPを利用することで全頂点に対して「自身を根としたときの DP の値」が O(N) で求められる。

Python3