问题描述
对于长度为 $1\le n \le 10^5
$ 整数数组 $a
$,计算所有的数对 $\lfloor \frac{a_i}{a_j} \rfloor
$ 之和,其中 $\lfloor \frac{a_i}{a_j} \rfloor
$ 表示向下取整,$0\le i,j \lt n,1\le a_i \le 10^5
$,结果对 $10^9+7
$ 取余。
示例:
|
|
问题分析
方法一:遍历
最简单的办法就是遍历所有的数对:
|
|
但是这样的复杂度为 $\mathcal{O}(n^2)
$,对于 $10^5
$ 的数据会超时。
方法二:整数分块
对于整数 $n
$,
- $
\lfloor \frac{n}{i} \rfloor
$ 的结果最多只有 $\sqrt{n}
$ 数量级个 - $
a=\lfloor \frac{n}{i} \rfloor=\dots=\lfloor \frac{n}{j} \rfloor
$ 中 $[i,j]
$ 的范围是连续的 - $
j=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor
$,即如果知道了知道了 $i
$,可以在 $\mathcal{O}(1)
$ 时间内求出 $j
$
|
|
时间复杂度为 $\mathcal{m(\sqrt{m}+\log(n))}
$,$m
$ 为数组中的最大值,虽然二分搜索 $i,j
$ 可以通过频率前缀和数组处理 $\mathcal{O}(1)
$ 得到,但是还是 $\mathcal{O}(m\sqrt{m})
$ 的复杂度,对于 $10^5
$ 的数据也会超时。
方法三
对于整数 $x
$,
- $
x,x+1,\dots,2x-1
$ 除以 $x
$ 的结果为1
- $
2x,2x+1,\dots,3x-1
$ 除以 $x
$ 的结果为2
- $
3x,3x+1,\dots,4x-1
$ 除以 $x
$ 的结果为3
- $
\cdots
$
所以,可以使用一个数组 freq
记录所有数出现的频率,prefreq
记录 freq
的前缀和。
这样对于 $x
$,prefreq[2 * x - 1] - prefreq[x - 1]
就表示除以 $x
$ 结果为 1
的个数。
|
|
时间复杂度为调和级数的和,复杂度趋近于 $m\log(m)
$,$m
$ 为数组中的最大值。
方法三与方法二其实原理相同,不过是反过来求。方法二是将数 $
x
$ 作为分子,方法三是将 $x
$ 作为分母,即方法二是求商的个数,方法三是求积的个数。