AGC032

1時間半くらい前に37.0で、今日は体調もいまいちと感じていたので不安になるが、開始前には36.5くらい(忘れた)で気分も落ち着いていた。Bを通した直後は37.3でヤバかった。つらくはなくて頭も回っていたのでよし。2回のAGCをいいパフォーマンスで切り抜ける(その言い方はどうなんだ)ことができて嬉しい。今は36.7。微妙では。早く書き上げて寝ねば。

A - Limited Insertion

難しすぎる。Aが400点と聞いて、パフォーマンスが低く出る現象を気にしていた。Aが解けるか解けないか微妙なラインの人たちが、解けた場合は提出して解けない人は提出しない(不参加扱いになる)ため、このA問題が得意な人たちだけが参加することになり(罠でそうじゃないこともありそうだけど)、その上のレート帯の人たちが割を食う。700点のB問題もクソムズだった場合を考えると、Aの早解きで人権を得ておきたい。しかし難しい。危機感で便意が(すぐ引っ込むタイプの)。Aは必ず解けると思ってやってるので、ここまで難しいとリズムがとれない。順位表を見ると、強い人は通せてるので、まあ思いつけばというところかと。

色々な例をいじってみるが、どうもすっきりしない。逆から見るのも典型なので当然考えるが、なかなか。12345より大きいのは無理でそうじゃなきゃできそうなんだけど、具体的な手順が見えない。さて、小さい数を何回右へ押し出せばいいかという視点で考える。どのくらい過去から存在しないといけないか。逆に大きい数は右のほうにあるし、右のほうにあるということは右に押される機会も多い。ん、単に逆から考えて、数を取り除いていく。取れる数のうち、最も右のものを取ればよさげでは。行けそうなので実装する。1-indexedなのでかなり書きづらい。0-indexedにするのも2回変換入るしなあという微妙なところ。さて、さすがに雰囲気で提出するのは怖い。最も右のものを取れば、(12345の屋根の下に入っているという意味で)状況が良くなっている?ということで提出。AC。いや、悪くなってるけどギリギリのやつが存在しないから1低くなっても平気なんだ。

解説を読むと、明快でいいですね。

B - Balanced Neighbors

どこから考えていいかわからないが、C問題も知らない用語でアレなので頑張って考える。Nが小さいケースを考えてみる。4のときは解けた和を5にできる。5は、複雑そう。4のケースがけっこうきれいなので、6も同様にやってみる。1と6、2と5、3と4をペアにする。自分が属するペアと異なるペア一つに辺を伸ばす。一つだとそこで完結してしまってダメか。出力するグラフは連結でなければならない。そこで、自分が属さない全てのペアに辺を伸ばす(つまり、自分のペアの相手にだけ辺を伸ばさない)。well-definedか微妙に不安だったが、一応これで解けている。偶数の場合はOK。奇数が難しいパターンか(そういうのが過去にあった(と思う))。さて、奇数の場合もペアを作ってみる。5、1と4、2と3、という3ペアを作る(あ、5は単独だからペアじゃねえ)。これも全部の和引く5になっているのでは?解けた。実装だが、偶奇の場合分けをどうしたらきれいにできるかなかなか見えない。グラフ出力部分は、完全グラフを出力するみたいにして、ペアの相手だけ除く。構築ゲーは、できてることそのものが証明になるのでやりやすい。

C - Three Circuits

サーキットがいくらググっても出てこないのでびっくりした。「頂点素」という言葉の意味もまあわかるが、「辺素」をサーキット同士で辺を共有しないことと捉えると「頂点素」もサーキット同士のことになり、一つのサーキットで同じ頂点を2回使っていいのか確信が持てない。初めてコンテスト中に質問した。すぐ答えてもらって(同様の質問は多かったのだろう)、「同じ頂点を何度も訪れてよい」ことがわかった。あとから考えるとアレだが、当時は本格的に取り組む前の段階。初めて目にする単語の意味に確信が持てないのはまあ仕方ない。

閉路が3個あればいい。全部の辺を使う必要があるので、次数が1の頂点が存在したらその時点でダメ。次数が奇数でも、その頂点を閉路が通過したとき残された1本が使えなくなるのでダメだ。3つというのは置いといて、全部の次数が偶数なら、いくつかのサーキットで覆うことはできそうだ。えーと、まず一つの閉路を発見する(行き止まりがないので必ず一つはある)。それ(その閉路を構成する辺たち)を取り除くと、残ったグラフも偶数なので閉路が一つとれる。つまり、偶数なら、いくつかの閉路に分解できる。

色々な図を描いて経験値を溜める。しばらくして、トライフォースみたいなサンプルを思いついた。6頂点9辺。いまスカウォやってるので、このサンプルをパッと思いつかないようでは何のためにスカウォやってるんだと冗談で思った(冗談で思うとは)。同じ頂点に来たらそこで閉路とする。閉路を2つ取り除いてまだ辺が残っていれば3個以上。つないでサーキットは減らせるので3個以上ならOK。閉路が1個だけだとこれは無理っぽ。問題は2個のときだ。2つのサーキットが共有する頂点の個数?3個以上だとたぶんできる。1個は無理そう。2個も無理そうだなあ。証明はできないけど、時間もないのでとりあえずこれで書いてみる。閉路を求めるの苦手感。理解してないんだよなあ。まあ書けることは書けるので、面倒な実装をザクザクと進めていく。さて、閉路を2回とるときに、同じ辺を使わないようにするにはどうしたら??内部では有向グラフになってるから、逆辺も除かないといけない。かなり困ったが、std::setでなんとかする。忘れがちだが2回だけでいいので、わりと無理が利く。頂点の訪問済みフラグもビットで持ったが、2回なので普通にO(N)でクリアできた(そもそも回数が少ないから32bitで足りると自分で判断しといてこれだからね)。なかなかサンプルが通らないが、頑張ってデバッグ。バグは取れていったが、ついにサンプルが通らないまま時間となった。

Cは解けなかったけど楽しかった。サンプルが通らなかったのは、ビットフラグをandじゃなくxorで判定してたから。全部xorで行けると思っちゃう。また、閉路を探すとき数字の6みたいになるケース(出発点と違うところに戻るやつ)が抜けてて酷かった。