2021年1月26日火曜日

CodeChef - Killing Monsters

それぞれのモンスターについて、どの時点まで生きているかが高速に求まればよい。

クエリ(x,y)(x, y)が与えられたとき、xxに(bit集合の意味で)包含されるようなすべての番号のモンスターからyyを引くことになる。

  • f[t]:=x=tf[t] :=x =tであるようなクエリの総ダメージ。
  • F[t]:=xtF[t] :=x \supseteq tであるようなクエリの総ダメージ。

とするとき、関心があるのはFFで、FFffからゼータ変換で得られる。各クエリを処理した時点でのFFが配列としてqq個分すべて求まっているとすると、それらをクエリ番号に関して二分探索することで各モンスターがどの時点まで生きているかがわかる……が、FFを毎回作ると間に合わない。

そこで、クエリをBB個ずつに分割して、q/Bq/B個のクエリ番号に対してのみFFを作ることにする。 モンスターkkがどの分割まで生きているかを線形探索(あるいは二分探索)で調べて、そこからはモンスターが死ぬまでクエリを一つずつ見ていく。

前半の計算量はO((q/B)nlogn){O}((q/B) n\log n)で、後半はO((q/B+B)n){O}((q/B + B)n)B=qlognB = \sqrt {q \log n}とすると全体の計算量はO(nqlogn){O}(n \sqrt {q \log n})となる。