数列GCD
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数列GCD相关的知识,希望对你有一定的参考价值。
数列 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的主要内容,如果未能解决你的问题,请参考以下文章