整除分块(数论分块)
介绍
在求解问题
n ∑ i = 1 ⌊ n i ⌋ ∑ i = 1 n ⌊ n i ⌋
时,若 n n 的范围很大那么 Θ ( n ) Θ ( n ) 求解将会超时,我们需要一种更高效的方法来计算,整除分块就是这样一种方法
不难发现,在 i i 取某些值的时候 ⌊ n i ⌋ ⌊ n i ⌋ 的值都是相同的,考虑将 ⌊ n i ⌋ ⌊ n i ⌋ 的值相同的 i i 一起计算,减少计算次数
那么此时我们需要计算多少次呢?
当 i ≤ √ n i ≤ n 时显然 ⌊ n i ⌋ ⌊ n i ⌋ 的取值只有 √ n n 种可能,而当 i > √ n i > n 时有 n i < √ n n i < n ,所以 ⌊ n i ⌋ ⌊ n i ⌋ 的取值同样只有 √ n n 种可能,也就是说 ⌊ n i ⌋ ⌊ n i ⌋ 的取值只有 2 √ n 2 n 种可能,对于同样的取值只用计算一次,总的时间复杂度也就是 Θ ( √ n ) Θ ( n )
下面来说具体怎么做
画出 ⌊ n i ⌋ ⌊ n i ⌋ 的图像不难发现,所有取值相同的 i i 都是连续的整块的,这也是这个算法叫做整除分块的原因,对于每一块我们想要通过给出这一块的左端点,Θ ( 1 ) Θ ( 1 ) 计算出这一块的右端点,这样才能保证复杂度
假设现在我们的左端点是 l l ,那么设 ⌊ n l ⌋ = k ⌊ n l ⌋ = k ,我们要求右端点也就是最大的 r = l + d r = l + d 使得 ⌊ n l + d ⌋ = ⌊ n l ⌋ = k ⌊ n l + d ⌋ = ⌊ n l ⌋ = k
把 ⌊ n l ⌋ ⌊ n l ⌋ 和 ⌊ n l + d ⌋ ⌊ n l + d ⌋ 展开得 n = k l + p n = k l + p 和 n = k ( l + d ) + p ′ n = k ( l + d ) + p ′ ,其中 1 ≤ p < l 1 ≤ p < l
那么 k l + p = k ( l + d ) + p ′ k l + p = k ( l + d ) + p ′ 所以 p ′ = p − k d p ′ = p − k d ,因为 p ′ ≥ 0 p ′ ≥ 0 ,所以 k d ≤ p k d ≤ p ,所以 d ≤ p k d ≤ p k ,又因为 d d 为整数,所以 d d 最大能取 ⌊ p k ⌋ ⌊ p k ⌋ ,其中 p = n mod l = n − l ⌊ n l ⌋ p = n mod l = n − l ⌊ n l ⌋ ,k = ⌊ n l ⌋ k = ⌊ n l ⌋
所以我们有
r = l + d max = l + ⌊ p k ⌋ = l + ⌊ n − l ⌊ n l ⌋ ⌊ n l ⌋ ⌋ = l + ⌊ n ⌊ n l ⌋ − l ⌋ = ⌊ n ⌊ n l ⌋ ⌋ r = l + d max = l + ⌊ p k ⌋ = l + ⌊ n − l ⌊ n l ⌋ ⌊ n l ⌋ ⌋ = l + ⌊ n ⌊ n l ⌋ − l ⌋ = ⌊ n ⌊ n l ⌋ ⌋
也就是说,对于每一个左端点为 l l 的块,它的右端点为 ⌊ n ⌊ n l ⌋ ⌋ ⌊ n ⌊ n l ⌋ ⌋
求 n ∑ i = 1 ⌊ n i ⌋ ∑ i = 1 n ⌊ n i ⌋ 我们从左端点 l l 为 1 1 开始枚举,每次右端点 r r 取 min ( n , ⌊ n ⌊ n l ⌋ ⌋ ) min ( n , ⌊ n ⌊ n l ⌋ ⌋ ) ,将答案累加上 ( r − l + 1 ) ⌊ n l ⌋ ( r − l + 1 ) ⌊ n l ⌋ ,然后令 l = r + 1 l = r + 1 不断循环,当右端点等于 n n 时停止循环
练习
练习一
Luogu P3935 Calculating
题目大意
给定 n n 求 n ∑ i = 1 d ( i ) ∑ i = 1 n d ( i ) ,其中 d ( i ) d ( i ) 表示 i i 的约数个数
题解
1 1 到 n n 的约数显然只能也在 1 1 到 n n 内,那么考虑换一种方式表达 n ∑ i = 1 d ( i ) ∑ i = 1 n d ( i ) ,枚举 1 1 到 n n 的所有数,看枚举的数属于多少个数的约数,假设当前枚举到数字 k k 那么在 1 1 到 n n 内 k k 属于多少个数的约数,那么也就是在问在 1 1 到 n n 内 k k 的倍数有多少个,显然有 ⌊ n k ⌋ ⌊ n k ⌋ 个,题目也就转换为了求解 n ∑ i = 1 ⌊ n i ⌋ ∑ i = 1 n ⌊ n i ⌋ ,整除分块即可
练习二
P2261 [CQOI2007]余数求和
题目大意
给定 n , k n , k ,求 n ∑ i = 1 k mod i ∑ i = 1 n k mod i
题解
k mod i k mod i 可以写作 k − i ⌊ k i ⌋ k − i ⌊ k i ⌋ ,原式即变为 n ∑ i = 1 k − i ⌊ k i ⌋ = k n − n ∑ i = 1 i ⌊ k i ⌋ ∑ i = 1 n k − i ⌊ k i ⌋ = k n − ∑ i = 1 n i ⌊ k i ⌋ ,考虑对于 n ∑ i = 1 i ⌊ k i ⌋ ∑ i = 1 n i ⌊ k i ⌋ 使用整除分块,对于值相同的 ⌊ k i ⌋ ⌊ k i ⌋ ,利用等差数列求和公式算出 i i 的区间和,再乘以 ⌊ k i ⌋ ⌊ k i ⌋ 就可以 Θ ( 1 ) Θ ( 1 ) 累加进答案
再看整除分块时 n , k n , k 的上界问题,当 n ≥ k n ≥ k 时 i > k i > k 的部分贡献均为 0 0 ,所以我们忽略 n n 比 k k 大的部分,直接以 k k 为上界计算 k ∑ i = 1 ⌊ k i ⌋ ∑ i = 1 k ⌊ k i ⌋ 即可;当 n < k n < k 时每次右端点变为 min ( n , ⌊ k ⌊ k l ⌋ ⌋ ) min ( n , ⌊ k ⌊ k l ⌋ ⌋ ) ,右端点到 n n 时停止
该文为本人原创,转载请注明出处
博客园传送门
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】