AOJ 2005 - Water Pipe Construction
解法
設置コストを辺の距離とみなすと、結局何かしらの距離の最小値を求めるような問題に帰着できそうな気がします。ここで、制約に注目すると、が100以下であり、[tex:O(N3)]が通ることから、ワーシャルフロイド法が使えそう、ということがわかります。
さて、問題の条件を満たすための条件は、から、からに向かう経路が存在することで、これらの経路の距離の総和が最小になればよいです。
ここで、上の経路に含まれる以外の辺は絶対に使わないので、以下のような2パターンのみに限定できます。
1つめは、図の左側のような、どこかの頂点までは、共に同じ経路をたどり、で分岐するようなパターンです。
2つめは、図の右側のような、の経路の途中にそもそもが含まれているパターンです(もちろん、とが逆でもよいです)。しかし、これは、からの距離を0とみなしてしまえば、と分岐点が一致したとみなすことができます。
ということで、あとはありうる分岐点が通りあるので、それぞれについて、の距離の総和を求め、その最小値を取ればよいです(もちろん、そもそも経路が存在しなければ無視します)。
感想
解法のポイントに気づいて注目すると、考察がすぐに終わるパターンですね。今回は、分岐点と、制約のの部分でした。
350点問題でもこのような問題があるので、サクサクといていきたいですね。
AtCoder Petrozavodsk Contest 001 D - Forest
解法
まずは、全ての木を連結にするには、それぞれの木について、頂点を少なくとも1つ選んで連結にする必要があるので、それぞれの木から、最もコストが小さい点を1つずつ選んでおきます。
また、コストを最も少なくして全てを連結にするには、頂点の木にする必要があります。ので、辺は本新しく張る必要があり、そのためには個の頂点を使う必要があります。
が、それぞれの頂点は1回ずつしか選択できないので、の場合、全ての木を連結にすることはできません。
逆にそれ以外の場合は、最初に選んだ点の個数をとして、個の頂点を、個に含まれない頂点の中から、コストが小さい順にとっていけば、それらの頂点をうまく組み合わせることで、全ての木を連結にすることができます。
解法
解説を聞くと、あーなんだそれだけか、となるような問題でした。この手の問題を安定して解けるようになりたいですね。
AtCoder Petrozavodsk Contest 001 C - Vacant Seat
解法
インタラクティブ問題なので、二分探索を考えていきます。
まずは、どこか1つの席の情報がわかっていないと何も始まらないので、番の席を特定します。
ここが空席ならばその時点で終了、女性だったならば、男性だった場合と真逆のことをかんがえればよいので、男性だった場合について考えていきます。
番目が男性だった場合、番、番…の席に、男女交互に配置すると下の図のようになります。
ここで、青が男性、橙が女性を表します。
このままだと、図のようにと番目の席に座る人が、どちらも男性になってしまいます。
なので、これを回避するために、の区間のどこかしらに、空席が存在しているはずです。
次に、番の席の情報を特定したとします。空席ならばその時点で操作が終わるので、それ以外について考えます。
上の図で割り振った男女男女…は、席の番号が偶数ならば男性、奇数ならば女性になっているはずです。
番目の情報は、この偶奇に対する男女と一致しているか、していないかの2択です。
- 一致している(が奇数ならば男性、偶数ならば女性)場合
この場合、からまでの席は、 空席が1つもなく、男女交互に座っている、もしくは空席が存在している、の2パターン存在しています。
つまり、この部分は、空席が存在していない可能性があるので、この区間を今後探索するのは効率が悪そうです。
一方、からまでの席は、最初の状況と同じで、もし仮に以降も男女交互で並んでいるとすると、と番目の席について矛盾が生じます。
ということは、少なくとも1つはこの部分に空席が存在しているはずです。
よって、結局はについて、同じ探索を行えばよさそうです。
- 一致してない(が奇数ならば女性、偶数ならば男性)場合
このパターンは先ほどと逆の状況になります。
からの区間は、男女交互に配置しても条件を満たすことができるため、空席が存在するかもしれませんし、存在しないかもしれません。
逆に、からの部分については、男女交互に配置すると矛盾が生じるので、空席が確実に1つは存在します。
よって、こちらのパターンについては、について同じ探索を行えばよさそうです。
上の状況を、どちらのパターンにころんでも効率よく行うために、を区間のちょうど真ん中にしてあげるとよいです。ということで、結果二分探索を行えばよいことになります。
結局、やることは
番の席について調べる。調べるべき区間をとする。
について調べる。についてクエリを出して、その部分が、仮にから男女交互に配置していった場合の情報と一致するかどうかを調べる。一致したら、次に調べる区間をとし、そうでなければとする。空席が見つかるまでこれを繰り返す
ということを行えばよいです。
感想
久々のインタラクティブ問題でした。AtCoderだと初めてかもしれないです。
あんまり経験がないので、インタラクティブといえば二分探索っぽいことをしたくなります。そこから考察をさらっと終わらせたのはよかったのですが、例によってデバッグで時間をかけました。
xorを利用して条件の一致を判定したので、その部分を丁寧にやる必要がありましたね…
AtCoder Petrozavodsk Contest 001 B - Two Arrays
解法
とを同じ数字にそろえる場合に、3パターンの選択の方法があります。
を選び、以外を選ぶパターン
はになり、は据え置きです。
この方法だと、かつが偶数の場合にそろえることができます。とを選ぶパターン
,になります。ので、の場合、これを行うことでそろえることができます。以外を選び、を選ぶパターン
,になります。
の場合にそろえることができます。
これらより、の際は、2つめの方法でいくらでも数を調整することができますが、の際は3つめの方法を使うしかありません。
しかし、3つめの方法を利用するには、その回数分だけ、同時に1つめのパターンも行うことになります。
ということで、結局は、1つめのパターンと3つめのパターンを同時に行い、3つめのパターンが必要な部分の数を全てそろえた後、残った部分を2つめのパターンを利用してそろえる、というのが確実な方法になります。
ここで、3つめのパターンを行う必要がある回数は、です。1つめのパターンは、である限り行うことができるので、最大で回行うことができます。
なので、結局問題の条件を満たすかどうかの判定は、
を満たしているかどうかと一致します。
感想
この問題、大学の友人との勉強会でも出題したのですが、説明が難しすぎます…
結局調べるべきことはシンプルなのですが、その発想に至るまでの経緯が少し複雑でした。
ABC102 D - Equal Cut
解法
パッと見とっつきにくい問題。
まずは、3つのうち、どこか1つの仕切りを固定して考えるとして、どの仕切りを固定すると見通しがよくなるかを調べます。
まず、右端の仕切りを固定することと、左端の仕切りを固定することによる見通しの良さに差はありません。
ので、端の仕切りを固定したパターンと、真ん中の仕切りを固定した2つのパターンで見比べていきます。
端の仕切りを固定したパターン
このパターンでは、最終的な4つの数列のうち、1つの総和が確定します。今回は、右端の仕切りを固定して、が固定されたと考えます。
すると、残った1つの長い数列を3分割して、うまく最適解を求める問題に帰着できます。が、この問題を解くのはあまり効率的ではないです。真ん中の仕切りを固定したパターン
このパターンでは、数列が2つにわかれ、それぞれで、もう一つずつ仕切りを置く形になります。
この時の最適な2つの仕切りの置き方を考えます。このとき、、がそれぞれ最小となるように仕切りを置けばよいです。
簡単のために、とします。実際の求める値のパターンは の4パターンであり、どのパターンでも、が最小になるようにすることで、値を小さくすることができます。こちらのパターンの方が、先ほどの仕切りの固定の仕方よりも見通しが良くなります。
ということで、真ん中の仕切りを固定して、そのパターンについての残りの2つの仕切りの置き方を探し、これを全探索すればよいです。
ということで、あとは、とある数列に対して、それを二分したときの、それぞれの総和の差の絶対値が最小になるような仕切りの置き方を求めることができればよいです。
が最小となるようなの分け方は、2通りの方法で求めることができます。どちらの場合も、累積和をあらかじめ計算しておく必要があります。
尺取り法で求める
累積和は、数列の要素が増えるにつれて単調増加します。ので、尺取り法を用いると、が数列の右端だった場合に、その数列の仕切りの最適な場所が、で前計算した後、で参照できます。とを見比べていって、の方が差の絶対値が少ない場合、に対するが求まったことになります。二分探索で求める
が最小になるということは、は、に最も近い値になっているはずです。ということで、累積和がこのような場所になる部分を二分探索で求めれば、で求めることができます。
これらのどちらかを利用すると、真ん中の仕切りをある位置に固定したときの、残り二つの仕切りの最適な配置がもしくはで求めることができるので、あとは真ん中の仕切りの位置を全探索していけばよいです。
感想
一見とっつきにくい600点問題ですが、丁寧に最適なパターンを調べていくと、解ける…ような問題です。累積和で前計算+αというパターンはよく見るので、抑えておきたいです。
AOJ 1155 - 如何に汝を満足せしめむ? いざ数え上げむ…
解法
構文解析です。
変数がP,Q,Rの3種類しかないので、それぞれについて、値が0,1,2だったパターンの通りを調べればよいです。
構文解析の処理を1つの関数にまとめて再帰をしている方法が提出コード1、それぞれの役割に分担して行っているのが2です。
とりあえず普段の方法が提出コード1のパターンだったのでそちらを書き、バグりにくい方法をしらべたところこのような記事が見つかったのでこちらも練習で書いてみました。が、構文解析らしいバグではなく、別の部分でバグを発生させ、1時間以上溶かしました…
基本的にはどちらのコードも、文字列を前から見ていって、文字ごとの処理をガリガリ実装していけばいいです。やはり、構文解析といえば、現在見ている位置関係のバグが発生しやすいので、そこに注意しながら書きます。演算の処理も、おとなしく言われた通り実装するしかないです。
感想
本番は、どっちで書くか悩み中です…が、実際、機能ごとに関数が分かれている方が見やすいといえば見やすいので、しばらくは提出コード2の方で練習してみようかなと思います。