最近のABCのCとかD、普通にむずいんだよな
まず、1つの行や列に、黒と白両方が置かれることはない。
「●・・●・・・○」みたいな配置を考えたとき、 混在していると必ず黒と白の境界が存在するので、その部分の駒が互いの利きに入ってしまう。
なので、行と列をそれぞれ、以下のグループに分ける。
「黒のみ置かれる行数 Rb」「黒のみ置かれる列数 Cb」「白のみ置かれる行数 Rw」「白のみ置かれる列数 Cw」として これらを決め打ったとき、その行・列を N×M のどこに配置するかは、以下のようになる。
また、以下がわかれば、
全体の置き方の個数は、これらの積となる。
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 と決め打てば、除外すべき置き方はどの行・列を空にするかを含めて、以下のようになる。
これを 0≤Rx≤Rb,0≤Cx≤Cb(ただし Rx=Rb かつ Cx=Cb を除く)の範囲で全探索し、
Rb×CbCB から除外すれば、fb(Rb,Cb) が求められる。
これも O(N2M2) で計算できる。
何の個数を (−1)k の k とすればよいか少し迷うが、「必ず空行・空列にすると定める行数+列数」とできる。
空行があってもよい条件でそれぞれの場合を求め、
その上で (N+M−Rb−Cb−Rw−Cw) の偶奇によって答えに足す正負を切り替えると、最終的な答えが求まる。
これなら前計算は必要なく、Rb,Cb,Rw,Cw の総当たりのみで済む。
相変わらず、包除原理はなかなか直感的には見えづらい。
なんでこんな解かれてるの?
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=N√Q 程度に設定すれば O(N√Q) となる。
本問題の制約では最大 108 となるが、、、 まぁ r を動かす範囲は右のグループほど狭まるなどの定数倍の削減があり、間に合う。