2020年1月25日土曜日

CodeChef Aarambh 2020 - Odd Topic

出現する整数が高々4000種類しかないので、4000個のcompact bit vectorを持ってすべてのクエリに対して累積和で計算する、みたいなムーブを最初にやってしまった。(部分点は取れる。) 結局、バケット法+bitset高速化をした。

簡単のために、数列aabbの長さは両方NNとする。aabbを長さBB毎に区切ってk:=N/Bk := N/B個の区間に分解し、さらにそれぞれの区間に対して長さ40004000のビット配列を保持する。このビット配列をα1,...,αk,β1,...,βk\alpha_1, ..., \alpha_k, \beta_1, ..., \beta_kとする。それぞれの区間について、出現する整数の奇遇を数えて

αi[x]:={1(整数xが区間内に奇数個ある場合)0(整数xが区間内に偶数個ある場合) \alpha_i[x] := \begin{cases} 1 \qquad (整数xが区間内に奇数個ある場合) \\ 0 \qquad (整数xが区間内に偶数個ある場合) \end{cases}

としておく。(βi\beta_iも同様)
各クエリの指定区間に含まれるバケットαi,βi\alpha_i, \beta_iのXORを取って、端の部分は愚直に数えれば、立っているビットの数が答えになる。出現する値の最大値をAAとすると、計算量はO(Q((N/B)(A/logA)+B)){O}(Q((N/B)\cdot(A/\log A) + B))B=Θ(NA/logA)B= \Theta(\sqrt{NA/\log A})ならO(QNA/logA){O}(Q\sqrt{NA/\log A)}。(/logA/ \log Aの部分はいわゆるbitset高速化)

コンテスト中は深く考えずにB=200B=200としたのだけど、計算量を見るとN\sqrt Nよりは大きいほうがよさそうだったのでB=1000B=1000としてみたら遅くなった。なにか勘違いしてるかも。


tmwilliamlinさんの提出を見たら、単純なbitsetの累積和で処理していた。それはそうだった…… O((N+Q)A/logA){\mathcal O}((N+Q)A/ \log A)

Egorさんは出現する整数のほうを下位5ビットごとに分割して、bitsetなしで通している。