GCD of Contiguous Subsequence 2

2 secs 1024 MB
take44444's icon take44444

解法1(DP解)

以下の説明では,xx の約数の個数を σ(x)\sigma(x) と表現します.
以下の SSLL を考えます.

Si,gS_{i,g} : AiA_iが最右である連続部分列で,最大公約数が gg となるようなものの部分列の長さの合計

Li,gL_{i,g} : AiA_iが最右である連続部分列で,最大公約数が gg となるようなものの個数

Si,gS_{i,g}ggAiA_i の約数でない場合は明らかに 00 であるため, 1iNgAiの約数g×Si,g\displaystyle \sum_{1 \leq i \leq N} \sum_{g \in {A_iの約数}} g \times S_{i,g} が求める答えです.よって,Si,gS_{i,g} が求まっていれば,O(N×σ(Ai))\mathrm{O}(N \times \sigma(A_i)) で答えを求めることができます.

次に,SSLL を求める方法を考えます.
SSLL について,以下の式が成り立ちます.

Si,g=gcd(Ai,g)=g(Si1,g+Li1,g)S_{i,g} = \displaystyle \sum_{\gcd(A_i,g')=g} (S_{i-1,g'} + L_{i-1,g'})
(ただし g=Aig=A_i の場合はさらに +1+1

Li,g=gcd(Ai,g)=gLi1,gL_{i,g} = \displaystyle \sum_{\gcd(A_i,g')=g} L_{i-1,g'}
(ただし g=Aig=A_i の場合はさらに +1+1

従って,

Si,gcd(Ai,g)S_{i,\gcd(A_i,g')} += Si1,gS_{i-1,g'} + Li1,gL_{i-1,g'}
Li,gcd(Ai,g)L_{i,\gcd(A_i,g')} += Li1,gL_{i-1,g'}

と更新することで SiS_iLiL_i が求まります.Si1,gS_{i-1,g'}Li1,gL_{i-1,g'}gg'Ai1A_{i-1} の約数でない場合は明らかに 00 であるため,計算量は O(σ(Ai1)logAi)\mathrm{O}(\sigma(A_{i-1}) \log A_i) です.従って,SSLLO(N×σ(Ai1)logAi)\mathrm{O}(N \times \sigma(A_{i-1}) \log A_i) で求まります.

ここまで,ある ii について, Si,gS_{i,g} のうち 00 でないものを緩く O(σ(Ai1))\mathrm{O}(\sigma(A_{i-1})) 個と見積もってきましたが,実はもう少し小さいオーダーで上から抑えることができます.AiA_i は,O(logAi)O(\log A_i) 個の素因数を持ちます.部分列の長さを増やしていったとき,その区間の最大公約数の素因数の種類数,素因数の数はともに単調減少します.よって, Si,gS_{i,g} のうち 00 でないものは O(logAi)O(\log A_i) 個です.

以上より,O(Nlog2Ai)\mathrm{O}(N \log^2 A_i) で答えを求めることができます.

(解法は違いますが,類題として,AiA_i の制約が 1Ai1051 \leq A_i \leq 10^5 と緩い代わりに,数列ではなく木上のパスで同じものを求めるabc248_gもこの機会に解いておきましょう.)

解法2(セグ木を使った解法)

testerのあぷりしあです。D問題と同じように、セグ木上の二分探索を用いて解く解法を紹介します。

以下、g(l,r)=gcd(Al,Al+1,Ar)g(l, r) = \gcd(A_l, A_l+1, \dots A_r) と定義します。
ll を固定して考えましょう。このとき、各 rr に対して、g(l,r)g(l, r) は広義単調減少します。
g(l,r)g(l, r) の値が減少する境目の rr (つまり、g(l,r)<g(l,r+1)g(l, r) \lt g(l, r + 1) を満たす rr )を考えると、その個数は高々 A[l]A[l] の約数の個数となります。
そこで A[l]A[l] の各約数について、セグ木上の二分探索によって rr を求め、rr についてまとめて計算することでかなり計算量を改善することができます。(Dの解説も参考にしてください。) しかしながら、この計算量は O(N×d(A)logNlogA)O(N \times d(A) \log N \log A)AA は数列AA の任意の要素、d(A)d(A) はAの約数の個数)であり、d(A)d(A) が最悪で 13441344 個もあるため間に合いません。

そこで、さらなる工夫として、境目が rr に対する g(l,r)g(l, r) をすべての約数について調べるのではなく、都度更新していくことを考えます。
最初、x=A[l]x = A[l] として、以下を境目が配列の端に到達するまで繰り返します。

  1. xx についての rr を求め、ansans に計算値を加える。
  2. xxを、gcd(l,r+1)gcd(l, r + 1) に更新する。

更新回数は、解法1と同様に g(l,r)g(l, r) の素因数の個数に着目することで O(logA)\mathrm{O}(\log A) であることがわかります。

以上より、O(NlogNlog2A)\mathrm{O}(N \log N \log^2 A) で答えを求めることができます。

解法1のコード例(Python)

解法2のコード例(C++)