整除分块
众所周知,在int的世界中,除法都是下取整的,那么当一个数除以其他的数的时候,会出现结果相同的情况,在计算有关一个数被一个区间处理的问题中,就可以利用这个性质。例如,求数n分别除以1-n中所有数的和。
C++
#include <iostream>
using namespace std;
typedef long long ll;
ll n, ans;
int main()
{
cin >> n;
for (int l = 1, r; l <= n; l = r + 1)
{
r = n / (n / l);
ans += (r - l + 1) * (n / l);
}
cout << ans << endl;
return 0;
}
这段代码可以解决上面的那个问题。但是他的原理是什么。
首先我们要定义l
和r
,他们表示n
除以l
到r
的任意一个整数都是同样的结果,包括l
和r
。
因此每一次循环都会有l = r + 1
接下来就是r = n / (n / l)
这个式子的推导有其他大神的证明,而且算法题中也用不到证明,而且我也不会,就不在这里写了,只写一下我的简单理解
以6 / 4为例,r = 6 / (6 / 4) = 6
当我们正常计算的时候
r
=
6
⌊
6
4
⌋
r = \frac{6}{\lfloor\frac{6}{4}\rfloor}
r=⌊46⌋6
其中 6/4本该是1.5,但是下取整之后变成了1,因为右边界是整除的结果,所以求出来的r是右边界。
或者可以认为除了右边界,其他整除相同的的值都是有所变化的,因为进行了下取整,只有右边界的是确切的值,进行下取整后仍是原来的值。所以我们可以轻松的求出其右边界。