1. 程式人生 > >數列GCD

數列GCD

不同 int 同時 different 多重 pos gcd -1 元素

數列 GCD

  數列的 GCD 具有一些很迷人的性質, 值得我用一個完整的頁面闡述.

  一般地, GCD 具有可並性: 設有互不相交的多重集合 S, T , 則 $gcd(S \cup T) = gcd(gcd(S), gcd(T))$ .

  如果我們給定一個數列 $A$ , 要求某個區間的 gcd , 那麽就可以使用線段樹, ST 表等區間合並的結構, 在 $O(\log n)$ 或 $O(\log ^ 2 n)$ 求解.

  數列的 GCD 還具備更多的性質.

  為了方便闡述, 設 $S_{l, r} = gcd(a_l, a_{l+1}, ..., a_r)$ .

  當 $l$ 一定時, 可以將 $S_{l, r}$ 看作一個 $r$ 的函數, 它具有怎麽樣的性質?

  1. 隨著 $r$ 的增大, $S_{l, r+1}$ 單調不上升, 前一個數一定是後一個數的倍數.

  2. $S_{l, r}$ 的取值個數的上限為 $O(\log n)$ , 因為若 $S_{l, r} \ne S_{l, r+1}$ , 那麽 $S_{l, r} \ge 2 S_{l, r+1}$ , 所以序列的所有區間的不同 GCD 個數為 $O(n \log n)$ .

  

  如何對所有 $l$ , 求出所有 GCD 不同的 r 的集合 $R_l$ , 即對於 $r \in R_l$ , $S_{l, r} \ne S_{l, r-1}$ .

  我們考慮利用連續性高效處理, 得到 $O(\log ^ 2 n)$ 的做法.

  考慮由 $R_{l+1}$ , 求出 $R_l$ . 由 GCD 的可並性可證明若 $S_{l+1, p} = S_{l+1, q}$ , 那麽 $S_{l, p} = S_{l, q}$ . 所以 $R_{l}$ 一定是 $R_{l+1}$ 的子集並上 $\left\{ l \right\}$ . 我們直接將 $R_{l+1}$ 中的所有元素對應的 GCD 進行更新和去重, 即可得到 $R_l$ .

  實現如下:

 1     static pair<int, int> tmp[S];
 2     int tot = 0;
 3      
 4     tmp[++tot] = make_pair(pos, w);
5 F(i, 1, Len) { 6 int g = gcd(w, Lis[i].second); 7 if (g != tmp[tot].second) 8 tmp[++tot] = make_pair(Lis[i].first, g); 9 } 10 11 memcpy(Lis, tmp, sizeof tmp); 12 Len = tot;

[HDU 5869] Different GCD Subarray Query

  題意

  給定序列 $A$ , 多次詢問某個區間的所有子區間的不同 GCD 個數.

  分析

  離線處理.

  維護 $R_l$ 的同時, 把 $R_l$ 產生的 GCD 對每個右端點進行貢獻.

  如果之前已經貢獻過當前這種 GCD , 那麽先清楚掉之前的貢獻.

1     F(i, 1, Len) {
2         if (Last[Lis[i].second] > 0)
3             add(Last[Lis[i].second], -1);
4         add(Last[Lis[i].second] = Lis[i].first, +1);
5     }

數列GCD