ABC160 F - Distributing Integers
解法
のみの場合について答えることができればあとはうまく伝播させて全方位木DPにしてしまえばよいので、の場合を考えます。
を根とする部分木についての、数字の配置パターン数
を根とする部分木の頂点数
とします。の計算方法については、よくある問題なので省略します。
数字の配置パターン数、というのは、その部分木に存在する頂点の数字を並び替えた数列のパターン数です。
について考えるとき、子の数列それぞれの要素をいったん同じものとみなして並べ方を考え、最後に子の数列それぞれのパターン数をかければいいことになります。
子それぞれの数列を持ってきて、マージソートのようにしてマージするパターン数がわかれば、の子の集合をとして、
となります。
マージのパターン数は、同じものを含む順列について考えていることになるので、
ここを参考にすればよく、
となります。
これでの場合について解けました。
あとは全方位木DPを用いればよく、それぞれは和と積で構成されているので、今みている頂点から根を子へうつす際に、今見ている頂点についての値を、全頂点についての計算から、うつす子の値を除いたものに計算しなおせばよいです。
Educational Codeforces Round 48 (Rated for Div. 2) D. Vasya And The Matrix
問題概要
要素の数列と、要素の数列が与えられます。
行列の行列で、それぞれの行について、全要素のxorをとるとに、それぞれの列について全要素のxorをとるとになるようなものが存在するならば1つ求めてください。
解法
行う操作がxorなので、全要素を2進数の桁ごとに見て、最後に合算すればよいことがわかります。
ので、これ以降はが0,1からなる数列で、行列も0,1からなるものを求めることだけを考えればよいです。
構築できない条件を探してみます。
0,1からなるということと、xorが絡んでいることから、偶奇に着目します。
すると、数列の総和と、の総和の偶奇が異なる場合、構築できないことがわかります。
数列の各値は、その行に存在している値の総和の偶奇と一致するように構築する必要があります。ということは、の総和は、行列の要素全てに対する総和の偶奇と一致しているはずです。
このことはにも同様のことが言えます。
よって、行列全体の総和の偶奇は、の総和の偶奇と一致していて、かつ、の総和の偶奇と一致している必要があります。
ということで、の総和との総和の偶奇が一致しない場合には構築できないことがわかりました。
では、一致している場合には構築できるかどうか、を見ていきます。
わかりやすく、の総和の偶奇で場合分けをします。
の総和、の総和が奇数の場合
これはすごくシンプルで、の値を決める場合、であれば1
、それ以外なら0
とすればよいです。
の要素が1
の際、その行(列)で1
となっている要素の個数が奇数個になっている必要がありますが、で1
となっている要素の個数が奇数個であるため、上記のような構築をすればよいです。の総和、の総和が偶数の場合
この場合は少々厄介です。
単純な構築ができなかったため、どこかに値を押し付けて、最後に微調整を加えることを考えます。
すると、
を、と一致させる
を、と一致させる
とすると、以外はうまく構築できます。
あとは最後に微調整をすればよく、をとすればよいです。
感想
こんな構築もあるみたいです。すごい。
いやこれ文章に起こしたら普通に正しかった https://t.co/xvelOu9ldK
— かっつ (@_KKT89) 2020年3月15日
構築問題 メモ
構築の思考パターンメモです。主にはまやんさんの構築まとめに載っている問題をを埋めていきます。
2べきを考える
+1および×2の遷移を作成して任意の値を構築
問題
提出コード
既にある文字列に対して、先頭の文字を両端に追加する→×2
既にある文字列に対して、先頭の文字と異なる文字を両端に追加する→+1
の操作となります。
解説にもあるように、aTa|b|aTa
のようなケースが作成できてしまうと、数が増えてしまうので、Tが回文とならないようにする必要があります。これは、文字の種類を3種類以上用意して、ローテーションで新しい文字を割り振ればOKです。
構築の実装は、一番上のビットから順番に見ていき、
今見ているビットが立っている→ビットを立てる(+1の操作)
今見ているビットが立っていない→ビットを立てない(操作なし)
を行い、その後で右のビットにうつる際に、×2の操作を行えば構築完了です。
のケースや一番最初に追加する文字の選択に気を付ければ終わりです。初めに1文字何か入れておけば問題ないです。
その他
ARC102 D - All Your Paths are Different Lengths
ARC102 D - All Your Paths are Different Lengths - ツバサの備忘録
までを上手く構築し、残りのについてもそれを利用して構築します。
特徴のあるグラフをベースに考える
完全グラフ
Tenka1 Programmer Contest (2018) D - Crossing
Tenka1 Programmer Contest (2018) D - Crossing - ツバサの備忘録
完全グラフそのものです。
スターグラフ
ABC132 E - Friendships
問題
提出コード
スターグラフをまず構築した後に、問題の条件を満たすまで辺を追加しつづけます。
木
頂点辺の単純連結無向グラフが与えられた場合に、適当な全域木を取って考えると見通しがよくなることがあります。
WUPC2019 C - Permutation City
再帰DFSをしつつ、葉の方から、今見ている頂点とその子に対して処理を行います。
AGC035 B - Even Degrees
問題
提出コード
こちらも同様、葉から見ていき、今見ている頂点の子の情報を集めた後、辻褄が合うように自身の状態を確定します。
ABC155 F - Perils in Parallel
問題
提出コード
前半の難しいパートを終えると、上の問題に帰着できます。
二部グラフ
日立製作所 社会システム事業部 プログラミングコンテスト2020 C - ThREE
問題
提出コード
適当に根を決めると、そこからの距離の偶奇で置くべき数字が変わってきます。
そこで二部グラフになっていることがわかり、あとは頂点数によって構築方法を場合分けします。
第一回日本最強プログラマー学生選手権-予選- D - Classified
二部グラフになればよく、頂点を決め打って奇数距離同士を結ぶ、偶数同士は別のレベルで結ぶ、を繰り返します。ビットを利用すると構築が楽。
XOR
Educational Codeforces Round 48 (Rated for Div. 2) D. Vasya And The Matrix
構築の典型というよりかは、XORの典型を用いるとスムーズにいく、という感じでしょうか。
しいて言うなら、とりあえずシンプルに構築して、最後に微調整を行う
という考えがポイントでしょうか…?
未分類
順列の和差昇順ペアを作成
差が昇順
のとき、の偶奇で場合分け
E - Rotation Matching
やることはどちらも同じで、前半部分で差が偶数のペア、後半部分で差が奇数のペアを作成する和が昇順
こちらはの偶奇で場合分け(でペアを作成)
E - Non-triangular Triplets
偶数の場合はという形でならぶ(奇数は等差)
TODO 昔の記事をまとめる
JOI2017/2018 予選 D - 水ようかん (Mizuyokan)
解法
- 番目までのようかんを切り終えて、ピースの最小値がになるように切り分けたときに取り得る"ピースの最大値"の最小値
とします。こうすることで、答えはで求めることができます。
すると、でピースを作成すると仮定した際に遷移がどうなるかを考えればよいため、として、
と考えたくなります。初期値はです。
しかし、このままではおそらくACすることはできません(参考)
以下のようなケースを考えます。
2 10 1
これは、サンプル2のようかんを左右反転させただけなので、明らかに答えは9
です。
しかし、上のままの解法だと、おそらく答えが合わないかと思います。
この原因は、上のDP解が左端のようかんが最小値になる場合のみについて考えていることによるものです。
このケースのように、右端が最小のピースになったり、3つ以上に切り分けたうちの真ん中が最小になるケースも存在します。
これを解消するために、DPの定義を少し書き換えます。
- 最後まで切り分けた結果、ピースの最小値が以上になると仮定したときの、番目までのようかんを切り終えたときに取り得る"ピースの最大値"の最小値
すると、遷移はそのまま、初期値はとすることで、このDPを計算できます。
答えも最初と同様で求めることができます。が、仮定と矛盾する場合、つまりピースの最小値が以上となる切り分け方が存在しなかった場合は排除しなければなりません。この場合は、になっているため、容易に場合分けをして排除することができます。
切り分け方は存在するが、ピースの最小値がぴったりにならないものも存在します。が、今回は以上、という仮定を置いているので、ぴったりにならない場合は、以降のどこかでぴったりになるはずです。は、が大きい方が値が小さくなるので、によって問題なく最小値を取り出すことができます。
AOJ 2312 - 魔法少女さやかちゃん
解法
添え字は0-indexedとします。
区間の総和は、BITや累積和を用いて高速に取得できるものとします。
とします。
仮に円環でなく直線上に音符を配置しているとした場合、明らかに音符をの昇順に配置するのが最適です。
しかし今回は、音符を並べて円環を作成しています。この場合、
となっているはずです。
つまり、円環を2つに分け、二本の直線とみなすと、それぞれが広義単調増加(減少)になっていればよいことがわかります。
あとは、を昇順でソートし、二本の直線のうちどちらに配置するか、ということを考えればいいことになります。ということで、以下のようなDPを考えます。
- 片方の右端が、もう片方の右端がになっているときの最小コスト(ただし、もしくは )
初期値はです。 の遷移は、場合分けで表されます。
の場合
この場合、と同じ直線にを配置することになります。よって、
となります。の場合
この場合、を配置した直線とは違う直線にを配置します。
つまり、と隣接する音符は、のいずれか(はのときのみ可能性が存在します)であるため、
(ただし)
となります。
これを計算すると、が答えになります。
AOJ 2826 - ゲームバランス
解法
倒すまでに最小回以上かかるなかで最大となるを二分探索で求めます。
ゲームクリアできない場合、になります。二分探索時は、ゲームクリアまでに回以上かかっている、と仮定します(最後に求まったを確認した場合にゲームクリアできなかった場合は答えが-1になります)。
以降は、ゲームクリアができると仮定して話を進めます。
そして、そもそも、の場合に戦闘が回未満になる場合は-1になります。これを排除しておきます。
を固定した際に、何回かかるかを調べます。
現在のレベルをとします、初期値は1です。
ここから、レベルがの際に一番レベルが上がる敵を毎回倒すことをシミュレートします。回を超えたらそれ以上シミュレートする必要がないので、そこで打ち切ります。を倒せるレベルになっていたら、その場合もシミュレートを終了します。
レベルが一番上がるのは、との差が最も小さい強さを持つ敵です。
そこで、強さ以上を持つ敵の中で一番弱い敵を二分探索で調べます。
そして、その敵が倒せるかどうかを判定します。
倒せる場合はその際に上がるレベルをメモします。
次に、先ほど調べた敵の1つ手前にいる敵について、上がるレベルをメモします。この際は、自分のレベルがのため確実に倒せることから、倒せるかどうかの判定をする必要はありません。
そして、今調べた2体のうち、よりレベルが上がる方を選択して倒します。
これを繰り返します。
AOJ 2966 - G トレジャーハンター (Treasure Hunter)
解法
解説の通りこちらを参考にして通しました。
再帰でDFSをしながらナップサックを解き、戻り値として、今いる頂点を使用した際の最適解配列と、使用しなかった際の最適解配列を返します。
今いる頂点をとします。子をとします。
1つめの子に対する再帰
引数で渡された配列をそのまま子の引数にします。
戻ってきた値について、
の処理は、それぞれの添え字について、で更新します。
についての処理は、今いる頂点と両方を使用するときは、コストがかかることに注意し、で更新します。2つ目以降の子に対する再帰
について考えます。
をまず引数にして再帰します。
そして、先ほどとほぼ同様の処理、具体的にはによる更新をします。
について考えると、知りたいのは、を根とする部分木についての最適解であるため、という配列を用意し、全てを0で初期化して、これを改めて引数として再帰します。
そして、得られた結果について、 で更新します。
これらの処理が済んだら、について使用する方はお宝の価値を加算して、を戻り値として返します。