Bracket Sequencing - abc 167 f

#かっこ列 #kyopro_friends さん #貪欲法

開いてる ")" が少ない文字列から左から埋めた方がいいか?

開いてる ")" というのは, 相手の "(" がいない ")"


ある時点で, "(" の数より ")" の数が多くなってはダメだから
それの相手の "(" が手前にいないとかっこ列にならない


次の方法で分析する
開いてる ")" の数は, 始め 0 として, "(" が来たら +1, ")" が来たら -1 する


f:id:tac_12:20200514154630p:plain:w300
f:id:tac_12:20200514152613p:plain:w300
f:id:tac_12:20200514154651p:plain:w300


折れ線グラフで, ペアになってるかっこの部分を引っこ抜く
上図の, 囲ったオレンジの部分


ペアになってるとこを全て引っこ抜くと谷になる
山があれば, ペアが残ってる


そして, その谷の下がってる部分が開いてる ")" の数


実は, 一番小さいところの数字である
上図の上から, -3, -2, 0


閉じてる ")" は, 相方の "(" による +1 を -1 する


かっこ列の条件は,
1. "(" と ")" の数が等しいこと,
2. すべての ")" に相方がいること


上の表現方法でいうと,
1. 最後の数字が 0 であること
2. 途中で負にならないこと


1. は文字列の順番に関係ない


開いてる ")" の数は 2. に関係するか?


開いてる ")" の数が小さい順に文字列を並べるのであった
すなわち, 最下点の数字が大きい順に並べる


では, 最下点の数字が同じ場合はどうするか
一番右端の数字が大きいほど, 次の文字列以降負の数が出にくい
スタート地点が高くなるから


さて, 一番右端の数字より最下点の数字を優先させていいか


下のテストケース 1 を見る
一番右端の数字より最下点の数字を優先して失敗する例
f:id:tac_12:20200514161007p:plain:w500


どうすべきか具体例で考えよう
2 つを比較する


最下点が -2 で右端が 5 の文字列 1 と, 最下点が -1 で右端が -1 の文字列 2 はどっちを先にすべきか


-2 するのが許されていて, -3 するのが許されていない状況にしよう
文字列 1 を先にすると, 高さが +5 になり, もちろん文字列 2 を置ける


文字列 2 を先にすると, 高さが -1 されて, 文字列 2 は置けない
高さが計 -1 - 2 = -3 になるところが出る


-2 すら許されていないとする
文字列 1 は先に置けない
文字列 2 を先においても, 文字列 1 は置けない


一般的に考える
最下点が 0 以上で右端も 0 以上の場合
問答無用で先に並べていい


最下点が負で右端が 0 以上の場合
この文字列を置くことで最下点が負になってしまうとする
残りの 2 つの場合の文字列を先においても, スタート地点の高さは減ってしまうので結局無理
よって, この場合の文字列の中で, 並びを考える


スタート地点 - 最下点 が負にならないのであれば, どの順番でもいい
なぜなら, 途中で負にならないのであれば, 結局高さが右端の値だけ大きくなるので, 足せるなら足す
+1 + 2 も +2 + 1 も変わらない


実は, 上 2 つの場合をまとめると, 右端の値が 0 以上であるなら, 最下点の数字が大きい順である
先に最下点が小さいのを置くくらいなら, 最下点が大きいのを置くことができて, スタート地点の数字を大きくできる


今まで左から文字列をつなげてきたが, 残り 2 つの場合は, 右から文字列をつなげれば, 上 2 つの場合と同じようにできる


左からつなげるなら, 最下点が小さい順


ソースコード
https://atcoder.jp/contests/abc167/submissions/13186315


テストケース
5

4
(((
)))((
))(
)

2
)(
)(

3
)
(
)))(((

4
))(
)(
)
((

5
)))((
)((
(
)(
)


Yes
No
No
Yes
No