一、题面
二、分析
参考文章:click here
对于整除分块,最重要的是弄清楚怎样求的分得的每个块的范围。
假设$ n = 10 ,k = 5 $
$$ i : 1 \ 2 \ 3 \ 4 \ 5 \ 6 \ 7 \ 8 \ 9 \ 10 \\ \lfloor \frac{k}{i} \rfloor : 5 \ 2 \ 1 \ 1 \ 1 \ 0 \ 0 \ 0 \ 0 \ 0 $$
我们推导出假设$ L = i $,那么,对应的 $ \lfloor \frac{k}{i} \rfloor $ 相等的最右边界为 $ R = \lfloor \frac{k}{ \lfloor \frac{k}{i} \rfloor } \rfloor $.(具体证明可以看参考文章。)
需要注意的细节是
1 $R$可能超过$n$,所以要限制一下。
2 一定要用$long long$。
三、AC代码
1 #include <bits/stdc++.h>
2
3 using namespace std;
4 typedef long long ll;
5
6 int main()
7 {
8 //freopen("input.txt", "r", stdin);
9 ll n, k;
10 while(scanf("%lld%lld", &n, &k) != EOF)
11 {
12 ll ans = n * k;
13 ll L, R;
14 for(L = 1; L <= n; L = R + 1)
15 {
16 ll res = k/L;
17 if(res)
18 {
19 // 必须加min,因为k/res可能超过n,例如 k = 10, n = 6
20 R = min(k/res, n);
21 }
22 else
23 R = n;
24 ans -= res * (R - L + 1) * (R + L) / 2;
25 }
26 printf("%lld\n", ans);
27 }
28 return 0;
29 }