洛谷2261:余数求和
洛谷2261:余数求和
题意描述
- 求\(\sum_{i=1}^nk\ mod\ i\)。
数据范围
- \(n,k\leq 10^9\)。
思路
-
我们知道\(a\%b = a - \lfloor\frac{a}{b}\rfloor*b\)。
-
那么我们上式就可以改写为\(\sum_{i=1}^nk-\lfloor\frac{k}{i}\rfloor*i=n*k-\sum_{i=1}^ni*\lfloor\frac{k}{i}\rfloor\)。
-
那问题就转化成了求\(\sum_{i=1}^ni*\lfloor\frac{k}{i}\rfloor\)。
-
打个表看看。
-
取\(k=5,n=8\)好了。
i=1 | i=2 | i=3 | i=4 | i=5 | i=6 | i=7 | i=8 |
---|---|---|---|---|---|---|---|
5 | 2 | 1 | 1 | 1 | 0 | 0 | 0 |
- 我们可以发现其实有好多\(\lfloor \frac{n}{i}\rfloor\)是一样的。
- 所以可以用分块的思想来做。
- 枚举块的左边界\(l\),右边界\(r=\lfloor \frac{k}{\lfloor \frac{k}{i}\rfloor}\rfloor\)。
- 这样的块大概有\(\sqrt{n}\)个。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, k, ans;
int main()
{
scanf("%lld%lld", &n, &k);
ans += n * k;
for(ll l = 1, r; l <= n; l = r + 1)
{
if(k / l != 0) r = min(k/(k/l), n);
else r = n; //当左端点大于k的时候,直接跳过
ans -= (r-l+1) * (l+r)/2 * (k/l);
} puts("");
printf("%lld\n", ans);
return 0;
}