OI 数论中的上界估计与时间复杂度证明
预备
0.1 渐进符号
其实不少高等数学 / 数学分析教材在讲解无穷小的比较时已经相当严谨地介绍过大 O、小 O 记号,然而各种历史习惯记法的符号滥用(abuse of notation)[1] 直到现在都让笔者头疼. These notations seem to be innocent, but can be catastrophic without careful manipulation. For example,
n=O(n2)∧n2=O(n2)⟹n=n2
Knuth 在《具体数学》里举出的例子[2]. “=” 隐含的对称性使其在 g(x)=O(f(x)) 中格格不入. 事实上,将 O(f(x)) 看作“阶不高于 f(x) 的所有函数的集合”是比“某个阶不高于 f(x) 的函数”更严谨的理解. 因此,本文将使用 f(x)∈O(g(x)) (有时也记为 O(f(x))⊂O(g(x)))的集合论符号代替传统的 f(x)=O(g(x)) 记法.
n2sinn∈O(n2)⟹∑i=1ni2sini∈∑i=1nO(i2)⊂O(∑i=1ni2)⊂O(n3) 或更一般的, g(x)∈O(f(x))⟹∑P(n,i)g(i)∈∑P(n,i)O(f(i))⊂O(∑P(n,i)f(i))
没看出有啥问题,对吧?笔者在写作此文时犯了同样的错误. 请注意,大 O 记号的作用对象是函数,f(i) 是什么?它只是个函数值,是确定的数——这是因为 i 也是求和枚举中确定的数,而不是 n 这种真正代表变元的记号. 所以 O(f(i)) 是什么?它什么也不是.
这种错误的出现是在所难免的,我们太习惯用 x、x3+5x2+x 这种变元都不明确的记号来表示函数了[1] . 写成 f(x) 也不严谨,因为只有 f 才应代表函数本身,f(x) 只能是函数值. 这样我们就可以放心地写下 O(f),不用担心把变元与确定值弄混了.
然而大家还是喜欢写 O(n2) 和 O(en2),而不是奇怪的 O(id2) 和 O(exp∘id2). 所以,我们大概只能沿用这种不太严谨的记号,并时刻提醒自己加倍小心了. (形如 x↦ex2 的 λ 风格“匿名函数”记号可能更好?)
但上述命题从结论上是正确的. 正确的推导过程应为 ∑P(n,i)g(i)≤∑P(n,i)Cf(i)≤C∑P(n,i)f(i)∈O(∑P(n,i)f(i))
第一步是直接由大 O 记号的定义得到的结果.
Wikipedia[3] 中有一张详尽的表格介绍了各种渐进符号的定义,OI Wiki[4] 上也有极好的讲解,尚不熟练的读者可以参考. 有兴趣仔细研究的读者可以参考《具体数学》第九章[2] 、Wikipedia 及其 reference(个人推荐 Knuth 关于 O、Ω、Θ 的短文[5] ). 本文除用 “∈” 和“⊂”替代 “=” 外,完全使用 Knuth 提议的记号体系.
0.2 调和数 H(n) / 调和级数
调和级数的部分和 H(n) 定义为 H(n)=∑i=1n1i 通过一些与 e 有关的数列放缩可以证明 limn→∞(H(n)−logn)=c,其中 c≈0.577 是 Euler 常数. 因此 nH(n)∼nlogn∈Θ(logn).
0.3 自然数等幂和 Pp(n) / p - 级数
p - 级数可视为调和级数的推广. 其部分和定义为 Pp(n)=∑i=1ni−p
p - 级数具有如下性质:
当 p>1 时,p - 级数收敛;
当 p=1 时,p - 级数是调和级数;
当 −∞<p<1 时,我们指出 Pp(n)∼11−pn1−p∈Θ(n1−p)
−∞<p<1 时 p - 级数的渐进估计可以从连续幂函数积分的角度理解. 证明这渐进性,离散情况下,可对 np 差分后前缀和 + 二项式定理得到高次项系数,或可用离散微积分理论得到精确表示(参见《具体数学》[6] );连续情况下,Lagrange 中值定理应为较简单的估计方法. 这里从略. 总之,我们得到: Pp(n)∈{Θ(n1−p)p<1Θ(nlogn)p=1Θ(1)p>1
1 约数函数 σz(n)
约数函数(Divisor Function,也可称为除数函数、因数函数)是与 n 的因子有关的一类函数,定义如下:
Definition 1 (约数函数) σz(n)=∑d∣ndz
当 z=0 时,σ0(n) 被称为约数个数函数(number-of-divisors function),常被记为 d(n) 或 τ(n). 当 z=1 时,σ1(n) 被称为约数和函数(sum-of-divisors function),常直接记为 σ(n).
Example 1 估计 σ0(n) 的渐进上界.
也就是估计 n 的因子的数量. 一个广为人知的上界是 2n,因为 n 的所有小于 n 的因子 d 均与另一因子 nd 一一对应.
事实上进一步可以证明 σ0(n)∈o(nϵ)∀ϵ>0[7] ,虽然这在 OI 中并不实用.
Example 2 估计 σ0^(n)=∑i=1nσ0(i) 的渐进上界.
即估计 1 到 n 中所有数因子个数的和. 这是一个形式上鲜为人知但其应用广为人知的例子. 变换求和顺序,容易得到
σ0^(n)=∑i=1nσ0(i)=∑i=1n∑d∣i1=∑d=1n⌊nd⌋≤∑d=1nnd=nH(n)∈O(nlogn)
显然,这比 O(nn) 的平凡估计好上不少. 本例的思路不仅是埃氏筛(Sieve of Eratosthenes)的理论基础,也在杜教筛、快速 Mobius 变换、gcd 卷积[8] 等处出现.
进一步利用此技巧和 p - 级数的估计,我们甚至能在仔细研究 σz(n) 前就得到其前缀和的渐进估计:
Example 3 估计 σz^(n)=∑i=1nσz(i) 的渐进上界.
σz^(n)=∑i=1nσz(i)=∑i=1n∑d∣idz=∑d=1ndz⌊nd⌋≤n∑d=1ndz−1=nP1−z(n)∈{O(nz+1)z>0O(nlogn)z=0O(n)z<0
遗憾的是,对此前缀和做差分并不能得到 σz(n) 的优秀估计.
现在引入一个重要放缩技巧,其在后续估计中屡试不爽.
Proposition 1 ∑d∣nf(d)≤∑i=1nf(⌊ni⌋)
显然,右式比左式多算了 i∤n 的项,因此命题是正确的. 但我们还可以做得更好:
Proposition 2 ∑d∣nf(d)≤∑i=1nf(i)+f(⌊ni⌋)
n 分治. 我们其实已经在 Example 1 估计 σ0(n) 时用过此技巧了.
Example 4 估计 σ1(n) 的渐进上界.
用 Proposition 1: σ1(n)=∑d∣nd≤∑i=1n⌊ni⌋≤nH(n)∈O(nlogn)
可以证明用 Proposition 2 不会得到更优的结果.
我们发现了一个有趣的事实:σ1(n) 和 σ0^(n) 的渐进上界均为 O(nlogn).
Example 5 估计 σz(n) 的渐进上界.
用 Proposition 2 和 p - 级数的性质:
σz(n)=∑d∣ndz≤∑i=1niz+⌊ni⌋z≤{2∑i=1n⌊ni⌋z≤2nz∑i=1ni−z=2nzPz(n)z≥02∑i=1niz=2P−z(n)z<0∈{2nzO(1)z>12nO(logn)z=12nzO(n1−z2)0≤z<12O(n1+z2)−1<z<02O(logn)z=−12O(1)z<−1={O(nz)z>1O(nlogn)z=1O(n1+z2)−1<z<1O(logn)z=−1O(1)z<−1
我们得到了一个相当优秀的渐进上界. 值得关注的是:
- 当 z=0 时,σ0(n)∈O(n12). 这与 Example 1 的结果一致.
- 当 z=12 时,σ12(n)∈O(n34),即 ∑d∣nd∈O(n34). 洛谷 P4980 Polya 定理模板题[9] 的一种比较 trivial 的解法[10] 的时间复杂度证明就来源于此. 我们之后还会在整除分块与杜教筛中见到它.
另外,如果只使用 Proposition 1 ,−1<z<1 部分的渐进上界将只能估计至 O(n). 因此 Proposition 2 是更为优越的.
约数函数更复杂的上限与渐进估计可参考 Wikipedia[7].
2 整除分块
也被称为数论分块. 求 ∑i=1nf(i)g(⌊ni⌋) 我们按 d=⌊ni⌋ 分块求和: ∑dg(d)∑⌊ni⌋=df(i) 可以证明,对一指定的 d,满足 d=⌊ni⌋ 的 i 取遍一连续区间,故若 f 的前缀和能 O(1) 求出,块数量 #{⌊ni⌋}i=1n 即该算法的时间复杂度. 注意到当 i≤n 时,⌊ni⌋ 最多只有 ⌊n⌋ 种取值,而 i≥n 时,1≤⌊ni⌋≤n 表明其也最多只有 ⌊n⌋ 种取值. 因此整除分块的时间复杂度 T1(n)=#{⌊ni⌋}i=1n≤2n∈O(n)
方便起见,后文记 D(n)={⌊ni⌋}i=1n.
2.1 整除分块嵌套
将 Proposition 2 加强,我们有如下通用放缩:
Proposition 3 ∑d∣nf(d)≤∑d∈D(n)f(d)≤∑i=1nf(i)+f(⌊ni⌋)
LHS 成立的关键在于 {d:d∣n}⊂D(n);而 RHS 的本质就是上述对整除分块块数量上界的估计.
注意到 Proposition 2 是 Example 5 证明的核心,而 Proposition 3 是 Proposition 2 的加强版,故仿造 Example 5 的证明,我们有
Example 6 令 Sz(n)=∑d∈D(n)dz 则前述 Example 5 中 σz(n) 的上界与渐进上界也同样适用于 Sz(n).
现在可以对嵌套整除分块 ∑i=1nf(i)∑j=1⌊ni⌋g(j)h(⌊nij⌋) 的时间复杂度 T2 做出估计了. 对 Example 6 取 z=12,立刻有 T2(n)=∑d∈D(n)T1(d)≤2∑d∈D(n)d=2S12(n)≤4nP12(n)∈O(n34)
我们还可以进一步归纳. 假定 ∀m≥0,∃zm:0≤zm<1,Tm(n)=O(nzm),我们有
Tm+1(n)=∑d∈D(n)Tm(d)≤C∑d∈D(n)nzm=CSzm(n)∈O(n1+zm2)
因此 zm+1=1+zm2. 边界条件 z0=0,数列递推求得 zm=1−2−m,检验满足条件. 因此 m 重嵌套整除分块的时间复杂度 Tm(n)∈O(n1−2−m)
3 杜教筛
杜教筛可以以低于线性的时间复杂度求解某些数论函数的前缀和. 其思路并不复杂. 设 f 为一数论函数,我们希望快速求得其前缀和 f^(n)=∑i=1nf(i). 考虑数论函数 g 和 h=g∗f, h(n)=∑d∣ng(d)f(nd) 两端做前缀和得 h^(n)=∑i=1nh(i)=∑i=1n∑d∣ig(d)f(id)=∑d=1ng(d)∑i=1⌊nd⌋f(i)=∑d=1ng(d)f^(⌊nd⌋)=g(1)f^(n)+∑d=2ng(d)f^(⌊nd⌋) 因此 f^(n)=1g(1)(h^(n)−∑d=2ng(d)f^(⌊nd⌋))
故若 g、h 的前缀和可 O(1) 算得,根据上式整除分块即可递归地计算出 f 的前缀和.
下面分析算法的复杂度. 注意到 ⌊⌊ni⌋j⌋=⌊nij⌋ 故单轮递归涉及到的自变量均可表示为 d=⌊ni⌋ 的形式. 一个 f^(d) 做整除分块耗时 T1(d),若采用记忆化递归,由上节分析,算法总时间复杂度为 ∑d∈D(n)T1(d)=T2(n)∈O(n34)
但我们还可以做得更好——考虑先用 O(K) 的时间复杂度线性筛出前 K 个 f(n) 并求前缀和,则递归求解时,d≤K 的 f^(d) 就无需再向下递归了. 为分析此类时间复杂度,对 Proposition 3 做最后一点扩展:
Proposition 4 ∑d∣nd>Kf(d)≤∑d∈D(n)d>Kf(d)≤∑K<i≤nf(i)+∑1≤i≤min{⌊nK⌋,n}f(⌊ni⌋)
特别的,当 K>n 时,有
∑d∣nd>Kf(d)≤∑d∈D(n)d>Kf(d)≤∑1≤i≤⌊nK⌋f(⌊ni⌋)
故用 Proposition 4 ,当 K>n 时,算法在递归部分的时间复杂度降低为
∑d∈D(n)d>KT1(d)=∑1≤i≤⌊nK⌋T1(⌊ni⌋)≤∑1≤i≤⌊nK⌋Cni=Cn∑1≤i≤⌊nK⌋i−12=CnP12(⌊nK⌋)∈nO((nK)12)⊂O(nK−12)
总时间复杂度为 O(K)+O(nK−12)
为最小化时间复杂度,取 K=n23,得到最优时间复杂度 O(n23).
这部分的时间复杂度证明主要参考了文章[11].
References
OI 数论中的上界估计与时间复杂度证明的更多相关文章
- SQL Server中关于基数估计如何计算预估行数的一些探讨
关于SQL Server 2014中的基数估计,官方文档Optimizing Your Query Plans with the SQL Server 2014 Cardinality Estimat ...
- [HRBUST-1688]数论中的异或(思维题)
数论中的异或 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 75(41 users) Total Accepted: 35(30 us ...
- 毫米波大规模阵列中的AOA估计
1.AOA估计在毫米波大规模MIMO中的重要性 在毫米波大规模MIMO的CSI估计中,AoA估计具有重要地位,主要原因归纳如下: 毫米波大规模MIMO 的信道具有空域稀疏性,可以简单通过AoA 和路径 ...
- 文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于肽段鉴定中错误发生率估计的能体现重复性的诱饵数据库)
文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于 ...
- 一些求和式的估算 & 杜教筛时间复杂度证明
本文内容概要: \(A=\sum\limits_{i=1}^n\dfrac1{\sqrt i}=1+\dfrac1{\sqrt2}+\cdots+\dfrac1{\sqrt n}\) \(O(\sqr ...
- acm数论之旅--欧拉函数的证明
随笔 - 20 文章 - 0 评论 - 73 ACM数论之旅7---欧拉函数的证明及代码实现(我会证明都是骗人的╮( ̄▽ ̄)╭) https://blog.csdn.net/chen_ze_hua ...
- $\mathcal{OI}$生涯中的各种数论算法的证明
嗯,写这个是因为我太弱了\(ORZ\). #\(\mathcal{\color{silver}{1 \ \ Linear \ \ Sieve \ \ Method \ \ of \ \ Prime}} ...
- Java中ArrayList和LinkedList区别 时间复杂度 与空间复杂度
一般大家都知道ArrayList和LinkedList的大致区别: 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问 ...
- 视觉SLAM中的深度估计问题
一.研究背景 视觉SLAM需要获取世界坐标系中点的深度. 世界坐标系到像素坐标系的转换为(深度即Z): 深度的获取一共分两种方式: a)主动式 RGB-D相机按照原理又分为结构光测距.ToF相机 To ...
- OI 数论整理
1.素数: 质数(prime number)又称素数,有无限个.一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数. 2016 ...
随机推荐
- XML_DTD_20200415
<!-- xml的注释写法 --> 格式良好的xml语言必须具备的几个条件 1.必须有xml声明语句,声明版本号与编码字符集 2.必须有且仅有一个根元素 3.标签大小写敏感 4.属性值 ...
- GDB 调试 - 正确地加载调试符号文件
一.开发流程 1. 编译可执行文件 1 #include <stdio.h> 2 #include <unistd.h> 3 4 void test() 5 { 6 char ...
- revit转tileset 3dmax转tileset cesium展示
使用revit软件导出fbx模型: 使用glTFExport导出gltf模型,导出的gltf模型具有属性.但是此处导出gltf模型,不是为了在cesium中加载该gltf模型,主要目的是获取组件属性信 ...
- Cross Site Scripting DOM (XSS) 攻击jQuery append() 的处理方法
做安全红线使用Fortify工具进行扫描时,jquery append会报Cross Site Scripting DOM风险.解决该问题有两种办法. 一.原生dom方式 使用JavaScript原生 ...
- java的死锁与解决方法
一.什么是死锁? 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无限等待. 二.产生死锁的原因与四个条件 2.1 死锁原因 竞争资 ...
- 开学考--MIS系统(javaweb的开学练习--网络新闻发布系统)
关于本次考试的相关理解 看到题目的时候,第一反应是这道题不难,之前已经做过十分类似的题目了,然后对于难度是很有自信的(当然,对于用户的权限管理部分,还是很懵): 而第二反应就是,题量挺大的,我在这有限 ...
- Python--相关环境的安装,以及hello world的实现
相关环境 进入官网:https://www.python.org/downloads/ 点击这里: 来到新的界面之后,向下滑动: 找到上图中的界面,选择版本进行下载即可. 具体的安装步骤可以参考这里看 ...
- Activiti7开发(二)-流程定义
目录 1.部署流程模型为流程定义 2.挂起/激活流程定义 3.删除流程定义 4.查询流程定义 5.上传并部署流程定义 6.查看流程模型 1.部署流程模型为流程定义 @PostMapping(value ...
- windows 系统下 workerman 在同一个运行窗口中开启多个 websocket 服务
目录 开启多个 ws 服务失败 开启服务失败解决办法 同一个窗口中运行 开启多个 ws 服务失败 正常情况下,如果你想开启多个 websocket 服务的话 只要在一个文件中,输入 new Worke ...
- Android 音视频采集那些事
音视频采集 在整个音视频处理的过程中,位于发送端的音视频采集工作无疑是整个音视频链路的开始.在 Android 或者 IOS 上都有相关的硬件设备--Camera 和麦克风作为输入源.本章我们来分析如 ...