gcd具有区间单调性:
对于gcd(l,r),l1<=l<=l2<=r2<=r<=r1,gcd(l2,r2)<=gcd(l,r)<=gcd(l1,r1)
gcd具有区间反向包含性质:
对于gcd(l,r),gcd(l1,r1),l<=l1<=r1<=r2,gcd(l,r)一定是gcd(l1,r1)的因子
区间内不同的gcd是有限的:
对于a【1】到 a【n】,设gcd【1,i】为a【1】到a【i】的gcd,则gcd【1,1】到gcd【1,n】中,至多存在log2n个不同的gcd值,这一点可以从gcd的反向包含性质中得出。
更进一步可以得出,gcd的变化是线性的。
也就是说,gcd【1,1】到gcd【1,k1】,gcd【k1+1,k2】…gcd【ki ,n】,每一段的gcd值是相等的
所以 ∑ i = 1 n \sum_{i=1}^n ∑i=1ngcd【1,i】=gcd1 * len1 + gcd2 * len2 + gcd3 * len3 + … + gcdk*lenk
记为 ∑ i = 1 n \sum_{i=1}^n ∑i=1ngcd【1,i】= ∑ i = 1 k \sum_{i=1}^k ∑i=1kgcd【k】*len【k】
因为至多有log2 n个不同gcd值,所以上面计算的复杂度便从o(n)降低到了o(log2 n)
来看一道例题
https://ac.nowcoder.com/acm/contest/625/H
题目大意:求一段区间中所有连续子序列的gcd之和;
我们可以这样子变形: ∑ i = 1 n ∑ j = i n \sum_{i=1}^n\sum_{j=i}^n ∑i=1n∑j=ingcd【i,j】= ∑ i = 1 n ∑ i = 1 k \sum_{i=1}^n\sum_{i=1}^k ∑i=1n∑i=1kgcd【k】*len【k】
原来是对O(n^2)个gcd求和,现在转化为O(nlogn)个数求和
然而对于 ∑ j = i n \sum_{j=i}^n ∑j=ingcd【k】*len【k】,我们并不知道分界点在哪,所以我们可以二分查找一段区间,对于gcd【c,l】,和gcd【c,r】我们查询gcd【c,m】,如果gcd【c,m】和某端点值相等的话,那么这一整段区间的值都是相同的,这里不加证明的给出这种计算的复杂度log(1e9)logn,然后我们查询可以用线段树维护,查询提供一个logn,加上n次计算 ∑ j = i n \sum_{j=i}^n ∑j=ingcd【k】*len【k】,一共是n(log^3)的算法复杂度,但这不是严格边界。
其中的log(1e9)logn很容易退化,这里数据不强应该能过
还没试过,有空试试看哈哈,只是自己想的一种办法