洛谷P2261 [CQOI2007]余数求和

题目

数论,考虑原题给的公式,得出\(i\%j=i-(i/j)*j)\)

原题求\(\sum_{i=1}^{i=n}(k\%i)=\sum_{i=1}^{i=n}(k-i*(k/i))=k*n-\sum_{i=1}^{i=n}(i*(k/i))\)

因此原题转化成了快速求\(\sum_{i=1}^{i=n}(i*(k/i))\)\(k/i\)在一段时间内是不变的,因此考虑数论分块。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, k, ans;
signed main()
{
    scanf("%lld%lld", &n, &k);
    ans = n * k;
    int l, r;
    for (l = 1, r; l <= n; l = r + 1)//l即i,r是满足k/l与k/r相等的数的最右边一位,易得k/(k/l)和n的最小值即为r,然后再用l,r的区间长度乘公差为1的等差数列的和,这样的时间复杂度是O(sqrt(n))的
    {
        if (k / l == 0) r = n;
        else r = min(n, k / (k / l));
        ans -= (k / l) * (r - l + 1) * (l + r) / 2 ;
    }
    printf("%lld", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/liuwenyao/p/11741726.html