(数论优化分块)P2261 [CQOI2007]余数求和

https://www.luogu.org/problemnew/show/P2261
给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
n,k <= 10^9
in:10 5 out:29

数据范围过大,考虑优化,想到a mod b = a - (a / b) * b,(a / b)为向下取整值
则答案求解的即是sigma(k - (k / i) * i) | 1<=i<=n -> n*k - sigma((k / i) * i) | 1<=i<=n
分析(k/i)发现可以将(k/i)相同的值分为一块,用该块的平均值及长度求出整块的值减掉
对一个左端点l,则(k / l)为该区间的值,右端点即为(k / (k / l))。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50 + 5;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    ll n, k;
    cin >> n >> k;
    ll 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;
        ans -= (k / l) * (r - l + 1) * (l + r) / 2;
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/84561159