整除分块
首先引入一个问题,若我们要求这么一个式子:
自然而然会想到这么一段翻译代码:
1 | for(int i=1;i<=n;i++) |
但是,如果 $1\le n\le10^9$,又该如何解决呢?
显然,$\left\lfloor\dfrac{n}{i}\right\rfloor$与$\dfrac{n}{i}$的不同在于,前者的值在某些情况下会出现区间性的大量重复。
下面我们来考察当 $n=10$时$\left\lfloor\dfrac{n}{i}\right\rfloor$的取值
我们可以发现:
显然重复部分(我们将他们成为块)占比很大,因此我们就找到了优化的突破口,如何优化在重复部分耗费的计算?
由于 $i$ 单调递增排列,因此重复部分是连续出现的,对于一个块$[l,r]$,若求出了 $l,r$就可以快速计算一整个块整除意义上的贡献。
经过思考可以得到$l$的初值必定为$1$,还有一个很显然的$l$ 的转移方程:
此时问题再次简单化,如何在已知$l$的情况下,快速求出重复部分右端点 $r$?
考虑 $r$的性质:根据$[l,r]$的定义可以得到$\left\lfloor\dfrac{n}{l}\right\rfloor=\left\lfloor\dfrac{n}{r}\right\rfloor$,我们将$\left\lfloor\dfrac{n}{l}\right\rfloor$表示为$k$ 。
此时有:
此时若使 $r$ 最大,则取等,即
此时,我们已经得到了快速求出 $l,r$的算法,因此对于大量的重复贡献,我么可以利用$[l,r]$区间快速得到总贡献,时间复杂度为$\Theta(\sqrt{n})$。
具体实现请看代码:
1 | for(int l=1,r;l<=n;l=r+1) |
我们习惯把以上优化算法称为整除分块(或除法分块、数论分块等),它可以优化以下类似式子的时间复杂度:
例题深化
1. UVA11526
模板题,翻译都不需要的那种,直接整除分块优化。(过~~~)
2.P3935 Calculating
题目大意:求
首先我们要知道 $n=p_1^{c_1}\cdot p_2^{c_2}\cdots p_m^{c_m},则f(n)=(c_1+1)\cdot(c_2+1)\cdots(c_m+1)$即为$n$的因数个数,可以由质因数的组合得到这个公式,这里不再详解。
回顾到这道题,要求区间$[l,r]$中的数的因子个数之和,自然而然就是类似于前缀和式的方法:求出$[1,l-1]$的因子和以及$[1,r]$的因子和,然后后者减去前者,就可以得到$[l,r]$的因子和。
可以知道,$[1,n]$中$i$的倍数有$\left\lfloor\dfrac{n}{i}\right\rfloor$个,即有$\left\lfloor\dfrac{n}{i}\right\rfloor$个数包含因子$i$。因此$\sum\limits_{i=1}^{n}f(i)=\sum\limits_{i=1}^{n}\left\lfloor\dfrac{n}{i}\right\rfloor$
然后又变成了整除分块裸题。
1 |
|
3.CF616E Sum of Remainders
题目大意:
求
很简单的一道推式子题,就是因为用上了整除分块才水上了紫。
由于块中的元素重复,我们可以提取公因数,因此乘 $i$可以在整除分块的过程中执行,不会影响效率,$\sum\limits_{i=1}^{m}\left\lfloor\dfrac{n}{i}\right\rfloor i$可以利用整除分块和高斯求和公式快速得到(不懂得可以停下来稍微想想)。
照水不误
- 运算过程中会爆longlong,取余很恶心
- 在这种恶心超大取余数论题中,常要预处理出某些除数的乘法逆元。
1 |
|
4.P2260 [清华集训2012]模积和
题目大意: 求
$\bmod 19940417$的值
对于这种式子很长,没有思路的题目,往往需要我们将式子拆开来才能找到考点。
考虑式子条件$i\ne j$的运算意义,就是在原有式子的基础上减去$i,j$重复部分,即
然后我们就可以愉快的手撕$\sum$:
我们使$m<n$:
这个式子结构性就很强了,我们可以考虑逐一求得式子各部分的值来得到最终答案。
part 1:$\sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)$
很显然就是上一题的结论与做法,不再赘述。part 2:$nm^2$
入门级运算part 3:$m\sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor i+n\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor i$
依旧是上一题结论,换汤不换药。part 4:$\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i^2$
看到这个式子我一开始就蒙了(太弱了),是不是式子柴得不够完全啊,然后就浪费了大量的时间来化简这个式子,最后还是做了无用功。
那到底应该如何处理呢?观察这部分式子,$\left\lfloor\dfrac{m}{i}\right\rfloor$与$\left\lfloor\dfrac{n}{i}\right\rfloor$都是我们熟悉的整除分块,但是要是将他们联系在一起$\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor$显然不是简单的直接分块相乘,那又该如何优化呢?借助上一题的思路,利用块的优化过程自然也要带上计算$i^2$,那是否 $\sum\limits_{i=1}^{n}i^2$也具有类似等差数列一样的求和公式呢(我太弱了不知道,在教练的帮助下推了好久才推出来)?
我们来模拟一下$\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor$的过程,考虑$n=20,m=17$
稍加思索可以发现,$\left\lfloor\dfrac{n}{i}\right\rfloor$所分的一个块与$\left\lfloor\dfrac{m}{i}\right\rfloor$所分的一个块的交集(公共部分)也是$\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor$的一个块。
稍微数学一点的表达:
有了这个概念,我们就易得$\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor$的块$[l,r]$的左右端点转移方程:
接下来我们考虑推导 $S_n=\sum\limits_{i=1}^ni^2$ 的通项式。
考虑
此时,我们已经解决了关于这道题的所有难点,有了二维整除分块以及$\sum\limits_{i=1}^ni^2$的求和公式,我么就可仿照类似上一题一般的方法优化$\sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor i^2$。
此时,我们首先化简题目的式子,然后对式子各部分进行逐一处理优化,最后得到了最终的算法:
处理以下函数
- $F_x:\sum\limits_{i=1}^x(x\bmod i)$
- $G_{x,y} :\sum\limits_{i=1}^x(y\bmod i)$
- $T:\sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor i^2$
最终答案为:$F_nF_m-nm^2+nG_{m,m}+mG_{m,n}-T$
1 |
|