AOJ 2443 Reverse Sort
解法
いろいろ嘘枝刈りBFSぽいことを考えましたが、全く解けませんでした…
↑こちらを参考にしました。
前から貪欲に揃えていくと、確実に回以内で揃える事ができます。
操作回数が増えると、たどり着ける状態が指数的に増えていきます。
なので、前(後ろ)からだけ見ていくのでは、最終的な状態が増えすぎてしまいます。
そこで、前から半分だけ、後ろから半分だけを見て、どちらからも行けるような状態が存在するかどうか、を調べます。
ということで、手だけ動かしてたどり着ける状態(と手数)を両方調べ、どちらにも存在する状態が無ければ、そうでなければそれぞれの手数の和の最小値を求めればよいです。
感想
半分全列挙の経験があまりなかったので、面白かったです。勉強になりました。
ABC166 E - This Message Will Self-Destruct in 5s
解法
もちろん、ペアを全探索することは難しいです。
ペアとしてカウントされる条件を詳しく見ていきます。
としたとき、カウントされる条件は、
となります。
これを式変形すると...
となります。
より小さくて、とペアになれるの個数は、上の条件を満たすの個数になります。
あとは、について前から見ていき、をそれぞれの値ごとにいくつ存在しているか、を見ればよいです。
やることは下の記事にある問題(と、そのページに貼られている類題)とほとんど同じです。
AOJ 2611 - 順位付け
解法
木の2乗DPとかなんとか言われてるやつです。
問題文をじっくり読むと、入力が木になっていて、そのなかで順位付けをしていくことがわかります。木全体の根は、入力時点で一番高さが高かった頂点です。
木の高さがすべて異なる場合は簡単に求めることができますが、同じ高さの場合があるのでさっと解くことはできません。
以下のようなDPを考えます。
- を根とする部分木について、高さの種類数がとなるようにしたときの、高さの決め方
頂点が葉だった場合は、となります。
それ以外の場合、子についてそれぞれ探索してから、自分自身にマージしていくことを考えます。
子についていくつか見た後の、現時点での値(高さが種類となるようなパターン数)
ここに、達をマージしていきます。は、今見ている子です。
とを組み合わせると、
新たな種類数はの区間のいずれかの値になります。
新たな種類数がになるパターンを考えます。
種類を組み合わせて種類にする際、
- 種類の中から、個を選び、側の高さを全て割り振る
という操作をまず行うと、種類の中から、すでに選択された個と、まだ選択されていない個にわかれます。
ここから、個の頂点に高さを割り当てなければなりませんが、この中で、個は残りの個のいずれかが選ばないといけないので無視します。
ということで、残った個の中から、個を選び、に割り当てる必要があります。
割り振る場所を決めてしまうと、順番は一意に決まるので、最終的に、種類を組み合わせて種類を作成する際のパターン数は、
通りです。
ということで、ここにをかけたものを、新たに足しこめばよいです。
このようにして、とを組み合わせて新たなを作成、という操作を繰り返します。
その後、最終的なについて、とすればよいです。今見ている頂点自身を種類数に加えるためです。
計算量についてですが、一見かかるように見えますが、一番内側のループ以外が合わせてになるみたいです。
詳しい解析はこちらを参照してください。
ABC164 D - Multiple of 2019
解法
ここでは、について下から桁目の数字をと表記します。また、の文字列の長さ、すなわちをとします。
加えて、をで割った余りをと表記します。
まず、について、桁ごとに分解して表現してみると、
となります。
は、次のように書くこともできます。
一般化すると、
ここで、
と定義してあげると、
と
の二つを組み合わせ、累積和のようにしてで計算することができます。
ここで、の桁目から桁目までを取り出した数( )は、これをとして、
が2019の倍数となるには、
となっていればよいです。
2019と は互いに素なので、先ほどの数式のうち分子のみに着目することで、結局
であれば、は2019の倍数ということがわかります。
これをさらに変形すると、
となり、結局
という条件であるようなのペアを探せばよいということがわかりました。
さて、この式は先ほど作成したそのものの式で、
であるようなのペアを探せばよいことになります。
となるようなの個数、という配列を用意しておき、
を計算
を答えに加算
に1加算
という操作を、から繰り返して行けば、答えが求まります。については、取り得る添え字の値がなので、そのサイズだけ確保しておけばよいです。
おまけ
今回のように、とを計算しながら答えを求めていく、というものはほかにもいくつかあります。
は、今回添え字が最大で2019にしかならないのであらかじめ配列を確保しておくことができましたが、そうでない場合でも、列の長さが以下のとき、種類も最大で通りにしかならないことを利用すると、map等を駆使することで計算ができます。
も、単純な累積和でいいもの等があります。
ほかにも、がと互いに素でないケースが存在する問題等ありますので、是非見てみると良いと思います。
類題リスト↓
AGCの200点でかなりの難関といわれた問題です。しかし、今回の問題を知っていれば、おそらく解けると思います。今回のような操作をする問題の解法ツイート等では、この問題名がよくあがります。
コーナーケースに注意しましょう。
少しトリッキーですが、帰着させることができます。
MIS.W新歓コンテスト2020
自分の大学にあるサークルが主催するコンテストに参加しました。
自分のコードはまとめてここに上げてあります。問題の前から順番にa,b,...と振ってあります。自分のコードを動かすことができるeの入力データも添えました。
長いのでかなり端折る部分があります。
コンテストリンク
- Mistale
- Join MIS.W!
- Okimochi Expression
- Random Card Battle
- SABAKAN FEVER
- Jewelry Construction
- MIS.W scheduling?
- Taberungo
- Contiguous Subsequences
- Dentaku
- 感想
Mistale
か、か、はたまたそのどちらでもないか、で場合分けをします。
サンプルに"Genocide"
となるケースが存在しないので、
10 10 0 0
などと入力してチェックをしてあげたほうがよいでしょう。
Join MIS.W!
から、それぞれで入力される人を引いていけば、最終的にすべてが0以下になっているかどうかで場合分けができます。
Okimochi Expression
の降順でソートし、得点が一番高い人について、"True"
であれば(初期値が0の)カウントを+1,そうでなければ-1として、カウントが正か負かはたまた0になるか、で場合分けをします。
Random Card Battle
が間に合うので、全てのについて愚直に試してしまえばよいです。
それぞれのカードについて独立なので、番目に勝てる確率の最大値について計算し、その総和を求めると答えになります。
に対し、を選択した場合、勝てる確率は
です。出す可能性のある得点を区間として見ると見やすくなるかもしれません。
SABAKAN FEVER
面倒な入力の部分必要だったのでしょうか問題自体はbitDPを用いて解けます。
の集合について、問題の条件に違反していないかどうか
とします。
それぞれについて愚直に見るとかかってしまいますが、
とある集合について、から一つの要素を取り出してとした場合に、が問題の条件に違反してたら、その時点でも問題の条件に違反してしまいます。そうでなければ、が、の要素と隣接していないかを調べることで、
に抑えることができます。
得点計算も愚直計算でそれぞれに対しでできるので、全体でで解けました。
ちなみに、グーグル翻訳に投げてローマ字に直せばいいや、と思っていたのですが…
Google Translate
問題の指定ではし
がsi
なのに対し、翻訳ではshi
になったり、北区がKita
とNorth
に表記ゆれしたり、台東区がTaito
とTaitung
で表記ゆれしたり、他にもいろいろあったりで大変でした。
Jewelry Construction
二人の持っている宝石を個とします。
よくよく考えると、となるのは、の場合のみです。それ以外の場合(とします)、最後にをA面に置いたのは明らかで、その結果となり、元々個だったのが個増えて個になったのだとわかります。
ここで、の場合、この場合も明らかに最後に宝石が増えたのはをA面に置いた場合であり、をA面に置いたターンは0倍であったことがわかります。
すると、0倍の操作については無視をして、となるようなの倍率で1回操作を行った、と考えてよいです。結局、になります。
これをお互い繰り返して行き、最終的に初期の条件、つまりになるかを調べればよいです。
この方法だと、初めに後手が個、先手が個持っているパターンが生じてしまい、のようなパターンで嘘解法になるように見えますが、この場合は、初手でとしてあげることで、上手く調整ができるようになっています。
これらの操作をうまくまとめると、結局であればOKです。にのみ注意しましょう。
MIS.W scheduling?
実装が破滅しました(その1)。
曜日、時間は全て分になおします。
まずは、サークル活動に重複がないかを調べます。重複があり、この時点で個すべてに参加できなければ"No"
です。
次に、全体で参加できる数を調べます。個の区間について区間スケジューリングで調べればよいです。
最後に、今調べた個数に、サークル全てに参加しながらたどり着けるかを調べます。
サークルとサークルの空き時間それぞれについて、尺取り法のようにしながら、講義を入れられるかどうか区間スケジューリングで試していきます。
サークルについて、0分開始、0分終了および、inf分開始、inf分終了という2つの番兵を入れてあげると楽になります。
Taberungo
食べるリンゴ個を決めたとき、それらを食べる順番は、明らかにが大きい順です。
なので、でソートをします。
あとは、ナップサックDPのようにして解けばよく、
- 番目までみて、個のリンゴを食べた場合に得られる満足度の最大値、とします。
で更新すればよいです。
Contiguous Subsequences
実装が破滅しました(その2)。
頑張って二分探索をします。
総和が以下となるような連続部分列の個数が個以上あるかどうか、については、しゃくとり法を用いることでで調べることができます。
連続部分列全体の個数が奇数の場合は、として一度二分探索をすればよく、
偶数の場合は、との2パターンについて調べ、その平均を取ればよいです。
Dentaku
足し算によって区切られるので、掛け算について考えます。足し算も同様にすればよいです。
+
で区切られる部分の連続する文字についての順列をまず考えます。
これはこんな感じで計算ができます。
次に、*
を入れる箇所について考えてみると、文字が個存在するときに、*
は個あります。
これらを左から並べていくときに、文字の個数と*
の個数には、という関係がなりたっていなければなりません。
左端は必ず文字なので、これを除くと、を満たすように文字と*
を並べる並べ方を求めることになり、これはカタラン数そのものです。ということで、ここを参考に計算すればよいです。
+
パートについてですが、+
で区切られる文字列を1つの大きな文字と見てあげて、*
と同じことを考えればよいです。
文字列について、辞書順ソート等できちんと並び替えることに注意すれば、この問題に答えることができます。
後は、計算した値の積を求めればよいです。
感想
実装で破滅した問題がいくつかあったので悔しいです。
典型っぽい考え方を使いつつ、面白い部分もたくさんあったので楽しかったです。
自分の中で400点問題と5,600点問題の難易度が逆転していました。
AOJ 2828 - マトリョーシカ
解法
元の問題について、体積の最小値ではなく、見えているマトリョーシカの個数を求める問題は、
最小パス被覆問題そのものになっています。これは二部グラフの最大マッチングに帰着させることができます。
sourse、sinkと、マトリョーシカそれぞれに対してin,outの2つずつ頂点を用意してあげます。
あとは、sourseから個のout、個のinからsinkに加え、マトリョーシカがをしまうことができる場合に、マトリョーシカのoutからのinに向け、それぞれ容量1の辺を張ればよいです。
体積の最小値の場合は、これを応用して重み付き二部マッチングによって解くことができます。
容量は全てそのままで、のoutからのinに向けて張った辺について、コストをの体積について符号を反転させた値とすることで、辺をカットする行為がの体積だけ得をすることに結び付けられます。
その他の部分でコストがかかることはないため0にしてしまえばよいです。
辺について一番異なるのは、最小費用流の場合、容量を流すと指定しなければならない部分で、最終的に一番外側になるマトリョーシカ分もフローを流さなければなりません。これは、それぞれのマトリョーシカのoutから、直接sinkにコスト0、容量1の辺を張ることで表現できます。
あとは、だけ流すのにかかるコストの最小を求め、その-1倍したものを、体積の合計から引くことで、最終的に一番外側になっているマトリョーシカの体積が求まります。
自分は、-1倍して解かずに、これを用いて解きました。2つのマトリョーシカを結ぶ辺については、、outからsinkに向けてはのコストに直します。すると、
が最終的に得をする分の体積になります。
AOJ 2703 - サイコロスタンプ
解法
あらかじめ、番目のサイコロが転がった結果記される数字と座標のペアリストを作成しておきます。
- サイコロの集合について、これらを最適な順番で転がした際に得ることができる得点の最大値
とすると、答えはです。
の求め方について考えます。
の中で、番目のサイコロを最後に転がした、ということを考えてみます。
このとき、と、番目のサイコロが通る座標で重複する部分があれば、から差し引かなければなりません。
ところが、重複する座標に今どの数字が書かれているか、というのはこれらの情報からは読み取ることができません。
ということで次に逆順、つまり、を最初に転がしたとき、について考えてみます。
このとき、と、番目のサイコロが通る座標が重複する部分について考えてみると、その座標に何がかかれていようが、番目のサイコロがその座標に書き込む数字は別のサイコロによって上書きされてしまいます。
ということで、の中で、最初にを転がした際に得られる得点の最大値は、
となります。
は、上記の計算をについて計算したうちの最大値となります。
です。自分は座標管理にmapを用いたので、が付きます。