CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning
解法
が回文になる条件は、a
~ z
について、に含まれる個数が全て偶数になる、もしくはどれか1つのみが奇数になる、のどちらかです。
a
, b
, ..., z
とします。
先頭の文字から番目の文字までを見て、奇数個になる文字について、を計算したものをとします。
が回文になる条件は、との排他的論理和を取った際に立つ2進数のbitが1個以下になる、というものに言い換えられます。
- 文字目までで、分割できる回文の個数の最小値
を考えると、
という遷移が成り立ちます。
ここで、はを2進表記した際に立つビットの個数とします。
これだけみるとになりますが、それぞれの2進表記で一番小さい値となるものをメモしておけば、27通りについて確認するだけで問題ありません(2進表記は、が累積xorを取っているだけなので最大通りです)。
あとはこれを計算し、を求めればおしまいです。
感想
とても面白かったです。
ARC099 E - Independence
解法
頂点との間に辺が張られていない場合、これらを同じ州に含めることができません。
これは全ての張られていない辺について成り立ちます。逆に、同じ州に含めることができない頂点対に辺を張ったグラフを考えると(これは与えられるグラフの補グラフです)、それぞれの連結成分が二部グラフになっている必要があることがわかります。
ということで、まず構築できる条件がわかったのでチェックします。
二部グラフ判定は、補グラフについてワーシャルフロイドを適用した後、全ての頂点のタプルについて、との距離の偶奇が、からの距離とからの距離の和の偶奇と一致しているかどうかを見ればよいです。
さて、辺の数を最小にする問題を考えます。
ある州に個の頂点を含ませた場合、そこに存在する辺の本数は
です。また、もう片方の州は個の頂点が存在しているはずで、こちらも同様に辺の本数を数えることができます。
ということで、州の個数がにできるかどうかを判定し、できる個数のうち辺が最小のものを選べば答えとなります。
あとは、個からなる州が作成可能かどうかわかればよいです。
先ほどの補グラフに再び注目します。
ある連結成分についてみると、二部グラフの頂点のグループは一意に定まります(適当な頂点からの距離を調べ、偶奇でグループ分けすればよいです)。
ですが、どちらのグループを州に含めるか、というのはそれぞれの連結成分ごとに自由に決められます。
ということで、
- 番目の連結成分までみて、個からなる州の集合が作成可能かどうか(bool値)
というdpが考えられます。
今見ている連結成分のグループの個数のペアがだった際、
という遷移を行えばよいです。
これで、作成できる州の頂点数がわかったので、あとは最小値を計算すれば終わりになります。
感想
補グラフと二部グラフがうまく考察できたので嬉しいです。面白かったです。
AGC029 D - Grid game
解法
高橋君が動かない、という操作を選択した場合、青木君は動かない、という操作を行ってゲームを終了させればよいので、高橋君が駒を動かさない、という選択肢は存在しません。
よって、高橋君が動けなくなるように青木君がうまく動けばよいです。
駒が列目にある際にゲームが終了すると仮定します。
青木君は、回、どこかで移動を行うことになります。
このときに青木君はどのタイミングで移動を行えばよいか?を考えます。
ゲームが終了するのは、という障害物が存在する場合で、かつに駒を動かすことができるときです。
この際に高橋君が行う操作の回数は、回です。
ということで、高橋君が行う操作の回数は、ストップする障害物の位置のみに依存し、青木君がどのような行動をとるか、には依存しません。
なので、できるだけ上の行に存在する障害物でストップさせたいので、極力はやく、列目に移動することが最適になります。
ということで、列目でストップする際は、
高橋君:常に移動する
青木君:列目より左に居た場合、右に障害物がなければ移動する、そうでなければ移動しない
という操作が最適になります。
あとは、列目でストップする場合の回数を全ての列について計算すればよいです。
列目に移動したときに何行目にいるか、というのは愚直にシミュレートすればよいです。
感想
すらすらと考察できたので、あとは実装スピードです。
AGC029 C - Lexicographic constraints
解法
種類以下で問題の条件を満たすような文字列たちを作成できるか?という問題を考えると、ある境界が存在し、それ以下では作成不可能、それ以上では作成可能になります。よって、あるについて問題の条件を満たすかどうか、を見ながら二分探索を行えばよいです。
先頭の文字列から順に見ていったときに、次に作成する文字列は、作成できる文字列の中で辞書順最小のものを選んだ場合が一番得をします。
なので、今作成し終えた文字列の状態を見て、次に作成する辞書順最小の文字列が何か?というのがわかればよいです。
文字列をランレングス圧縮のようにして、
文字目までがという文字になっている
という情報で書き換えます。
すると、次に作成する文字列の長さがであったとき、
であれば、辞書順最小の文字を末尾に追加
そうでなければ、すでに作成し終えている文字列の末尾のうち、以下でかつ未満の文字を次の文字に置き換え、その後辞書順最小の文字で埋める
という操作をすればよいです。
上記の条件を満たすような文字が存在しなければ、作成できないということになります。
感想
初手で貪欲に走ったので反省…
Typical DP Contest G - 辞書順
解法
まず、
- 文字目の次にという文字が現れるインデックスの最小値
を計算します。
これは、という更新を行えばよいです。
さて、
- 文字目を先頭で使った際にできる、部分文字列の種類数
というDPを考えます。
文字目を使った際に考えられるパターンは、
文字目の1文字のみ
文字目の次に、という文字を繋げる
の2つです(後者は最大26通りありますが…)。前者は明らかにトータル1通りです。
後者については、の直後に現れるを取ってくると、番目の文字の次にを置いたパターンの部分文字列が網羅できます。
なので、結局
という遷移になります。
では、最終的に求めたい文字列はどうなるでしょうか。
まず、先頭の文字がa,b,...z
であるような部分文字列全てについて足してもにならない場合は、明らかにEel
となります。
それ以外の場合は、前から貪欲、a
から順番に見ていき、総和が以上になるならその文字を選択…という操作を繰り返します。
実装の際は、先頭にダミーの文字を入れると実装が少し楽になります。
今見ているインデックスをとして、次に選ぶ文字をa
から順番に見ていきます。を見て、これが以上ならばが次の文字になります。そうでなければ、からを引き、次の文字をチェックしていきます。
今見ている文字が最後の場合となるパターンをから引き忘れないようにすれば、答えが求まります。
感想
最近ABCやその他の場所で、ある状態を構成し数え上げる際に重複するパターンを、貪欲にチェックする操作のみ考慮することで重複を消す、という考え方を使ってきたので、それと似たような考え方でできました。
それよりむしろ、メモリ制限が厳しかったです…空間計算量はまだまだ難しいですね
AGC009 C - Division into Two
解法
集合を、集合0、集合1とし、をとします。
- 番目の要素まで見て、番目の要素を集合に入れるような振り分け方のパターン数
を数えます。
という区間が集合に入り、その前後はもう片方の集合に振り分けられるパターンを考えます。このような操作ができる条件は、
の二つを満たすことです。
逆に、これらの条件を満たすについて、を集合に入れる、という操作ができるので、
という遷移が考えられます。
1つめの条件は、それぞれのについて二分探索を用いて計算ができます。
となるようなを二分探索で求めます。すると、 として選べるのは以下です。
2つめの条件は前計算ができます。
となるようなで区間を区切っていきます。
番目の要素についてみると、として選べるのは、その要素が所属している区間の要素のみになります。
以上で、ある要素について選べるの区間が求まったので、その区間の総和を求めてあげればDPの遷移が行えます。
区間和による遷移なので、累積和やセグ木で簡単に高速化ができます。
答えはです。
オイラーツアー、HLD解いた問題まとめ
提出場所見失いそうなので個人用まとめです
もう少し解法の中身っぽいところを後で加えたいです(加えてください)
HLD
Submission #12187038 - 2010年 日本情報オリンピック春合宿OJ
Submission #12180953 - AtCoder Beginner Contest 133
#491538 (C++17(1z)) No.529 帰省ラッシュ - yukicoder
HLDのupdate関数を使うこと!!!