浅谈整除分块

微笑、不失礼 提交于 2020-03-20 10:28:24

整除分块是一个挺简单但是应用极广的算法。

听上去挺难,实际不难。

实则它是解决这样一类问题:

求:

\[\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor\]

你可能觉得这个式子无法下手,连个 \(\gcd\) 也推不起来。

我们下面证明一个结论:

\(\lfloor \frac{n}{1} \rfloor\)\(\lfloor \frac{n}{2} \rfloor \cdots \lfloor \frac{n}{n} \rfloor\) 中,

不同的数值 最多\(2 \times \sqrt{n}\) 个。

证:

首先, \(i \leq \sqrt{n}\) 的时候,肯定取值不超过 \(\sqrt{n}\) 个。

其次,\(i > \sqrt{n}\) 的时候,会有:

\[\lfloor \frac{n}{i} \rfloor < \sqrt{n}\]

这个性质不明白,可以去重学因数了

所以,不同的取值也不超过 \(\sqrt{n}\) 个。(实际不能等于 \(\sqrt{n}\),但是我们不在乎这点常数)

所以,总取值不超过 \(2 \times \sqrt{n}\) 个。

这是数学上的说法,在编程上说,我们忽略常数,就说是 \(\sqrt{n}\) 个(指时间级别)。

所以,本题可以迅速解决。

for(int i=1;i<=n;) {
    int t=n/(n/i); //表示和当前 n/i 一样的最大的数
    //比方说 n=100 , i=17 ;那 100/17=5,最大值就是 100/5=20
    ans+=(t-i+1)*(n/i); //区间求和,因为整段的值都一样
    i=t+1; //枚举后一段
}

(这是伪代码,大家欣赏下就行)

整除分块是常用技巧,一定要学会哦!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!