整除分块
好像只能用来解决一个类似于$\sum^n_{i = 1}\left \lfloor \frac{n}{i} \right \rfloor$这样的整数求和问题,只要是带这个的,那么复杂度最低就能降到根号级别的。
可以发现,比如n = 8这个求和的每一项是这样的
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
8/i | 8 | 4 | 2 | 2 | 1 | 1 | 1 | 1 |
那么就可以优化,把结果一样的放在一起分块处理。
分的块大概有$2\sqrt{n}$个,因为当i小于等于$\sqrt{n}$时,取值一共有$\sqrt{n}$种,大于也是一样的
1 | for (int l = 1; l <= n; ++l) { |
l和r表示这个区间内的数x除n都是d,即n/x = d
,累加即可,复杂度是根号的。
[CQOI2007] 余数求和
给出正整数 $n$ 和 $k$,请计算
$G(n, k) = \sum_{i = 1}^n k \bmod i$
其中 $k\bmod i$ 表示 $k$ 除以 $i$ 的余数。
因为k mod i = k - (k/i)*i
,考虑整除分块。因为(k/i)是等于d的,所以在l和r之间是一个等差数列,然后对着等差数列求和即可。
分两种情况,第一种n小于等于k,那就直接做就行。注意r不能大于n,所以还要和n取min。
第二种是n大于k,那么推一下式子:
做法和第一种类似,或者分开看利用最后一个式子
1 | void solve() { |
可能以后学积性函数要用到这个
评论