Zth's Blog

记录学习路上的点滴

0%

整除分块

引子

整除分块比较经典的一个例题

i=1nni,n<=1012

上取整也是一样的

如果我们直接暴力求的话, 时间复杂度是O(n), 肯定过不了, 于是就引出了整除分块的方法

整除分块

我们知道, 在整除意义下n/i可能等于n/j,而且i, j之间的数必然和i,j的结果相同, 也就是说, ni相同的i必然分布在连续的一段区间内, 那么我们统计答案时只需要统计每个连续区间的长度和端点就可以了, 可以证明这样的区间一共有O(n)

时间复杂度的证明

分两种情况

  1. i<=n

    对于 i<=n , 假设每个i的结果都不一样, 最多也只有 n 种不同的结果

  2. i>n

    对于 i>n, ni分布在 [0,n1],也就是最多只有 n

证毕, 整除分块的时间复杂度为O(n)

实现

既然我们已经证明了时间复杂度, 那接下来我们就想办法实现它

既然结果相同的i分布在连续的区间内, 那我们就通过两个端点l, r确定区间, 然后不断移动l, r就可以了

初始时, 设l = 1

  1. 计算出res=nl
  2. 确定r, r=nres
  3. 统计答案, l=r+1
  4. 重复上述过程, 直到l>n

关于第2步的证明

假设当前答案为res, 那么所有满足条件的i满足

i×res+d=n,0d=n%i<i

那么i最大时, d=0, 此时i=nres, 如果不能整除, 显然应该下取整

所以r=nres, 得证

代码就不上了

Update

更新一下向上取整的情况, 感觉较向下取整还是复杂了些。

初始时, 设l = 1

  1. 计算出res=nl
  2. 确定r, 如果res=1r=n, 否则r=nres1
  3. 统计答案, l=r+1
  4. 重复上述过程, 直到l>n

关于第二步的证明

假设当前答案为res,那么所有满足条件的i满足

res1<nires

转换成i的范围

nresi<nres1

把i转换成范围内的整数

nresi<nres1

nresinres11

所以i最大为nres11, 得证