问题描述
对于长度为 $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$ 作为分母,即方法二是求商的个数,方法三是求积的个数。