[数学基础] 10 数论分块
数论分块
简介
数论分块通常被用来以的复杂度快速计算形如的含有除法向下取整的和式,它的核心思想是将相同的数打包同时计算,主要利用了Fubini定理。
证明
1. 证明时间复杂度为
引理1 对于任意一个正整数,的数量级为。
- ,假设所有的取值均不同,则存在种结果
- ,则,取值同样有。
因此,所有的可能取值一定,即整数分块的复杂度为。
2. 证明算法的正确性
引理2 对于, 若满足,则所有满足条件的一定是一段连续区间的集合。
反证法,若不是连续区间,则一定,使得且。
,即,矛盾,故得证。
**引理3 **若满足的集合为,则只需要知道,就可以求出对应的。
显然,,下面就要证明
令,则,下面要证明是满足的性质的最大的整数。
- 满足的性质,即
,则,即。
又,则,即
因此
- 是使得成立的最大的数。
反证法,假如不是最大的数,则一定可以使得
,又
所以,又,所以矛盾,得证。
综上,即为令的最大的数
模板
ll H(ll n){
ll res = 0, l = 1, r;
while (l <= n){
r = n / (n / l);
res = res + (r - l + 1) * (n / l);
l = r + 1;
}
return res;
}
例题
P2261余数之和
给出,计算
数据范围:
(懒得自己写题解了,直接cpy洛谷题解orz)由题意得:
我们知道,
因此,
首先枚举块的左边界 ,并根据左边界和 计算出右边界 。
令 ,分两种情况讨论:
- ,则 ;
- ,则 。
右边界有了,每一块的和也就可以计算出了。
每一块的和 当前块的 当前块元素个数 当前块 的平均值
当前块处理完后,令 ,开始计算下一块,直到计算至 n。
ll n, m;
void solve(){
n = read(), m = read();
ll res = n * m, l = 1, r;
while (l <= n){
if (m / l == 0) r = n;
else r = min(n, m / (m / l));
res = res - (r - l + 1) * (m / l) * (l + r) / 2;
l = r + 1;
}
printf("%lld\n", res);
}
数论分块往往和莫比乌斯反演结合起来考察,因此进阶的部分放在可能会存在的莫反专题中一起讲解。
分类:
数学 / 数学基础
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现