∑ni=1kmod
显然,\lfloor k / i \rfloor 是最棘手的,我们要想办法简化计算。
证明单调性
-
观察 \lfloor k / i \rfloor,显然随着 i 的增大,这个式子是越来越小的。
-
又因为有向下取整符号,所以该式子取值只能是整数。
若我们设函数 f(x) = \lfloor k / x \rfloor。则画在坐标轴中应该是从高到低一条条横线。
上图是一条 f(x) = \lfloor 10 / x \rfloor 的图像。
证明该式子最多只有 2\sqrt{k} 个取值
分段讨论:
- 当 i <= \sqrt{k} 时,因为 i 是 1 到 \sqrt{k} 的整数,所以最多只有 \sqrt{k} 个不同的 \lfloor k / i \rfloor 值。
- 当 i > \sqrt{k} 时,\lfloor k / i \rfloor <= \sqrt{k},又因为式子取整了,所以式子只能取1 到 \sqrt{k} 的整数,故最多也只有 \sqrt{k} 个不同的 \lfloor k / i \rfloor 值。
综上所述,\lfloor k / i \rfloor 最多只有 2\sqrt{k} 个取值
有关 当 i > \sqrt{k} 时,\lfloor k / i \rfloor <= \sqrt{k} 的证明:
由于下取整,所以 \lfloor k / i \rfloor * i <= k ①
假设 \lfloor k / i \rfloor > \sqrt{k} ,有 \lfloor k / i \rfloor * i > \lfloor k / i \rfloor * \sqrt{k} > \sqrt{k} ^ 2 = k。②
① 与 ② 矛盾
通过以上步骤,我们可以知道这个答案由连续 2\sqrt{k} 段不同的取值组成,那么我们只需要确定每种取值是下界 l 和 上界 r。通过 \sum_{i = l}^{r} \lfloor k / i \rfloor * i = \sum_{i = l}^{r} \lfloor k / l \rfloor * i = \lfloor k / l \rfloor * (\sum_{i = l}^{r}i) 即可求得每一段对答案的贡献。(\sum_{i = l}^{r}i) 可以用等差数列求和公式计算。
已知下界求上界
假设我们知道一段相同取值的下界是 x,若能求出上界,我们问题便解决了。
猜想若下界是 x,上界是 r = \lfloor k / \lfloor k / x \rfloor \rfloor
第一步、求证 \lfloor k / x \rfloor = \lfloor k / r \rfloor
-
由定义式可知 r * \lfloor k / x \rfloor + q = k ③,其中 0 <= q < \lfloor k / x \rfloor,所以 \lfloor k / r \rfloor = \lfloor\frac{r * \lfloor k / x \rfloor + q}{r}\rfloor = \lfloor k / x \rfloor + \lfloor \frac{q}{r} \rfloor >= \lfloor k / x \rfloor
-
r >= \lfloor k / (k / x ) \rfloor = x,所以 \lfloor k / x \rfloor >= \lfloor k / r \rfloor
综上 \lfloor k / x \rfloor = \lfloor k / r \rfloor。
第二步、求证 \lfloor k / (r + 1) \rfloor \not = \lfloor k / x \rfloor
假设 \lfloor k / (r + 1) \rfloor = \lfloor k / x \rfloor
那么有 (r + 1) * \lfloor k / x \rfloor + q’ = k,其中 0 <= q < r + 1
把式子变化一下:
r * \lfloor k / x \rfloor + \lfloor k / x \rfloor + q’ = k ④
③④ 联立,有:
\lfloor k / x \rfloor + q’ < \lfloor k / x \rfloor
因为 q’ >= 0,所以该式子矛盾,故假设不成立。
通过这两步及之前的单调性,我们知道 \lfloor k / \lfloor k / x \rfloor \rfloor 一定是上界
算法
所以算法就很好设计了:
- 设 l = 1,算出上界 r。计算这段的贡献
- 使 l = r + 1,即跳到下一段计算贡献。
- 重复知道算完 [1, n] 里所有段。
Tips:
- 当 \lfloor k / l \rfloor = 0 的时候,显然这段以及后面(有单调性)已经没有贡献了,可以 break。(或者直接设右端点为 n)
- 注意右端点和 n 取个 min,因为 > n 没有贡献了。
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
int n, k, l, r;
LL ans;
int main() {
scanf("%d%d", &n, &k);
ans = (LL)n * k;
for (l = 1; l <= n; l = r + 1) {
if(k / l == 0) break;
r = min(k / (k / l), n);
ans -= (LL)(k / l) * (l + r) * (r - l + 1) / 2;
}
printf("%lld\n", ans);
return 0;
}
你们柚子÷都这么强吗
代码比lyd清晰(
请问,在不知道答案的情况下,是如何想到 r=⌊k/⌊k/x⌋⌋ 的啊,能给一点思路吗?
一般猜,看看样例。
钦定了t后观测一个区间满足k/x=t,那差不多这个x上届就是再除一下吧,那股劲
大佬,当i>sqrt(k)时,\lfloor k/i \rfloor 能==sqrt(k)吗?
不行吧
所以上边那个小于等于是不是要改成小于(膜拜下%%%)
总结的太好啦!会写了会写了!谢谢大佬!
” r>=⌊k/(k/x)⌋=xr>=⌊k/(k/x)⌋=x,所以 ⌊k/x⌋<=⌊k/r⌋ “
作者大大,这一句的最后应该是>=符号哈
刚刚看到,已改正,不好意思哈
%