一、题面
二、分析
参考文章:click here
对于整除分块,最重要的是弄清楚怎样求的分得的每个块的范围。
假设$ n = 10 ,k = 5 $
$$ i : 1 2 3 4 5 6 7 8 9 10 \ lfloor frac{k}{i} floor : 5 2 1 1 1 0 0 0 0 0 $$
我们推导出假设$ L = i $,那么,对应的 $ lfloor frac{k}{i} floor $ 相等的最右边界为 $ R = lfloor frac{k}{ lfloor frac{k}{i} floor } floor $.(具体证明可以看参考文章。)
需要注意的细节是
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 ", ans); 27 } 28 return 0; 29 }