Loading [MathJax]/jax/output/CommonHTML/jax.js

目次

AtCoder Beginner Contest 242 F,G問題メモ

AtCoder Beginner Contest 242

最近のABCのCとかD、普通にむずいんだよな

F - Black and White Rooks

F - Black and White Rooks

問題

解法

まず、1つの行や列に、黒と白両方が置かれることはない。

「●・・●・・・○」みたいな配置を考えたとき、 混在していると必ず黒と白の境界が存在するので、その部分の駒が互いの利きに入ってしまう。

なので、行と列をそれぞれ、以下のグループに分ける。

「黒のみ置かれる行数 Rb」「黒のみ置かれる列数 Cb」「白のみ置かれる行数 Rw」「白のみ置かれる列数 Cw」として これらを決め打ったとき、その行・列を N×M のどこに配置するかは、以下のようになる。

また、以下がわかれば、

全体の置き方の個数は、これらの積となる。

fb,fw をDPで求める

Rb,Cb,Rw,Cw の全探索は O(N2M2) で可能なので、あとは fb,fw を前計算などで O(1) で得られればよい。

重複を避けるため、fb,fw は必ず空行・空列のない置き方で無いといけない。

B=3 Rb=3 Cb=2
OK      NG      NG      1つめのNGの置き方は、
●・・  ●・・  ●●●  Rb=2 Cb=2 を探索したときに既に数えられている
・●●  ●●・  ・・・

重複を気にしなければ、Rb×Cb 個のマスの中から置く B マスを選べば良いので、Rb×CbCB

そこから空になってしまう行数・列数を Rx,Cx と決め打てば、除外すべき置き方はどの行・列を空にするかを含めて、以下のようになる。

これを 0RxRb,0CxCb(ただし Rx=Rb かつ Cx=Cb を除く)の範囲で全探索し、 Rb×CbCB から除外すれば、fb(Rb,Cb) が求められる。
これも O(N2M2) で計算できる。

Python3

包除原理で求める

何の個数を (1)kk とすればよいか少し迷うが、「必ず空行・空列にすると定める行数+列数」とできる。

空行があってもよい条件でそれぞれの場合を求め、

その上で (N+MRbCbRwCw) の偶奇によって答えに足す正負を切り替えると、最終的な答えが求まる。

これなら前計算は必要なく、Rb,Cb,Rw,Cw の総当たりのみで済む。

相変わらず、包除原理はなかなか直感的には見えづらい。

G - Range Pairing Query

G - Range Pairing Query

なんでこんな解かれてるの?

問題

解法

TLE解法

SegmentTreeなどでは解きづらい。
1種類の値 x に限定すれば、SegmentTreeを使って区間 [l,r] に含まれる x の個数を取得し、 2で割って切り捨てることで x で作れるペア数は O(logN) でわかるが、 それをAi の値の種類数… O(N) 回繰り返さなければならない。全部で O(QNlogN) で余裕のTLE。

1つの値を1bitで管理してXORでマージすれば、「ペアにできない x が存在するかどうか」がわかり、 popcountして区間長から引くことでペア数もわかるが、それもbit長が O(N) になり、XORの演算に時間がかかるため無理。

公式解説の解法

Mo's Algorithm、クエリ平方分割を使う。なんか名前だけ聞いたことあった。

以下のような場合に使える。

今回の場合、現在の区間内の各値の個数(の偶奇)を管理しておけば、以下の要領で区間を1つ伸縮したときの答えを更新できる。

何らかの順序でクエリを並べ替え、その順に区間を伸縮させて答えを求めていくことを考える。

例えば r の昇順でクエリをソートし、この順に区間を伸縮させて答えを求めていくと、
右端の伸縮は最小限となるが、左端の伸縮で毎回 O(N) かかってしまう場合がある。

1              |-|
2 |----------------|
3                 |-|
4 |-------------------|

そこで、l を、なんか適当なブロックサイズ B でグループ分けする。

その中ごとに r の昇順でクエリを処理すると、左端の伸縮も1クエリ当たり最大 O(B) で収まる。

  <-B->
1     |-|
2 |---------|
3     |--------|
4 |-----------------|

分割した分、この処理をグループの個数 NB 回繰り返す必要があるが、

全体の計算量はこの和となるので、B=NQ 程度に設定すれば O(NQ) となる。

本問題の制約では最大 108 となるが、、、 まぁ r を動かす範囲は右のグループほど狭まるなどの定数倍の削減があり、間に合う。

Python3

オンラインの場合

クエリが先読みできないときも、別の方法で高速化は可能。