ABC248

5完。理不尽に順位が悪い。なんでみんなそんなに早解きできるの。まあんなこと言ったら前回は理不尽に順位がよかったと言わなきゃいけなくなるか。

A - Lacked Number

0から9までの総xorを求めておく。

B - Slimes

シミュレーション(制約を見て間に合うことを確認)。

すぬけくんが叫ぶ問題じゃん。これわかりにくいと思うんだよなw

C - Dice Sum

Mという上限があって異常に難しい。しばらく考えてDPでできると気づくが、Cで出していい難易度のDPじゃねえ。数列をi個目まで作って総和がhである通り数でDP。総和の上限を大きくとっておいて、Kより大きい領域へも配れば楽だったか。

D - Range Count Query

言語化しにくいが、A_iまで見て各数が何回現れたかの配列は各iについて順番に更新していける。ということはクエリ先読みで解ける。実装が思ったより重かった。数列上の位置とクエリ番号とクエリのXを保存して数列上の位置でソート。あとは数列の先頭からi個(iは0以上N以下のN+1通り)にクエリのXが何個あったかを記録していく。各クエリについて、記録された2数の差の絶対値(どっちがLでどっちがRが考えるの面倒なので)を求めて出力。

(解説を見て)思いつかなかった。

E - K-colinear Line

K=1は場合分けしておく。直線の傾きはO(N^2)個しかないので列挙する。傾きを固定したらあとはその直線と垂直方向の位置だけだが、N個の点についてどの位置になるか(直線と垂直なベクトルとの)内積で求めunordered_mapで分類し同じ位置にK個以上あれば直線1個をカウント。N=300のO(N^3)で定数倍が重いので1196ms。ACしたけど、C++でTLの半分を超えるのはよくない。もう少しがんばりましょう。

F - Keep Connect

FGを読んで少し考えどちらもわからないので順位表を見てFへ。全くわからない。包除かと思ったけどよく考えると非連結にするパターンが多すぎる。かなり解かれてるんだけど、本当に全くわからない。最終的に、6分遅れでAC。思いつくまでは「ABCなのにアドホックっぽいなあARCには出ないだろうけど」とか思ってたけど、ガチガチに典型だった。

残り20分を切ってきたあたりでDPを思いつく。いやあなんか「フローでさえ解けないものはDP」って思ってたけど、単に「俺が解けないものはDP」だ。はーなんだこのゲーム。競プロerはこれを見たらDPを考えるものなの?どうかしてるよ。(非連結が決まっていないもののうち)直前の上下2頂点が連結なもの、そうでないもの、既に非連結が決まっているもの、の3つに分ける。非連結が決まったものは捨てていいので2つだけでDPした(実装を進めないと気づかない)。遷移が地獄(3*3行列になりそう)。実際は5回配ればよかった。取り除く辺の数を3000より少し多く確保しておいて、その使わない領域へも配ることで楽に書ける。N-1回にわたって「コ」を付け加えていく。8通りあるので大変そうだが、全体の非連結が確定しないようにして上下対称とかも考えるとそんなに多くない。上下連結な状態からは、そのまま全部つなぐのと、1本だけ抜いても3通りとも連結なままだし、2本抜くのは上下非連結になって耐えるのが2通り。上下非連結からは、全部つないで連結にするか、横2本つないで現状維持するか。

G - GCD cost on the tree

(4/21追記)昨日の夕方から解説を見ながらぼつぼつやっていて、もう少しというところでぷよぷよの配信を見始めてしまい、なんとか寝る前にと思ったけど詰めると問題が2つも残っていたことに気づき寝た。起きてから改めて解説を見るとどちらも書いてあった。片方は「よく考えると」としか書いてなかったのでよく考えた。めちゃくちゃ長い道のりを経てAC。まだ24時間は経ってないのか。大量に休憩をはさみながら果てしなく続く道を歩いていた。

パスの長さ(辺数)ではなく頂点数なのが嫌らしい。約数ゼータ変換と聞いて解けるかもと思うがどこに適用するのか全く見えない。しばらく放置していたが、kyopro_friendsさんの解説をじっくり読んでいくことにした。パスの頂点数の和がGCD毎に求まればいい。そのためには、1から10^5までの各整数についてそれが公約数になるようなパスの頂点数の和がわかれば、それは求めるものを約数ゼータ変換したものだから逆変換(約数メビウス変換)で求まる。1から10^5までの各整数についてグラフを作りDFSすれば求まりそう。計算量がヤバそうだが、10^5個の森があっても頂点数の合計は高々N*(A_iの約数の個数の最大)にしかならない。各森に対しvectorに頂点番号を突っ込んでいく。jが公約数になる森について、各頂点からjの倍数だけを通ってDFS。約数メビウス変換は、篩で素数を求めながら各素数について引き算して累積和の差分をとっていく。頂点数の和の求め方が実はわからなくて、解説を見たら辺の寄与だった。既出E問題レベルのことがわからなかった。連結成分のサイズをK、DFSで辺に対応する部分木のサイズをLとすると、辺数の和であるΣ((K-L)*L)を求めたいが、これはK*ΣL-Σ(L*L)なので(KがLよりあとにしかわからないので困るが)Lを記録しておかなくても求まる。頂点数の和を求めるには、これに相異なる頂点のペアの個数を足す(Kから簡単に求まる)。もう一つの問題は計算量で、頂点数は大丈夫でもその隣の頂点も倍数になってるかチェックするので木がスターとかだと計算量が増えそうで心配になる。これはよく考えると元の全頂点から出ている辺の個数の和はO(N)だしそれが約数の個数倍になっても大丈夫(スターの中心の頂点が10^5個の森全てに出現するようなことはない)。なんか大丈夫そうな気はしてたけど本当によく考えないとわからなかった。