[BZOJ 1257] [CQOI2007] 余数之和sum 【数学】

题目链接:BZOJ - 1257

题目分析

首先, a % b = a - (a/b) * b,那么答案就是 sigma(k % i) = n * k - sigma(k / i) * i     (1 <= i <= n)

前面的 n * k 很容易算,那么后面的 sigma(k / i) * i,怎么办呢?

我们可以分情况讨论,就有一个 O(sqrtk) 的做法。

1)当 i < sqrtk 时,直接枚举算这一部分。

2)当 i >= sqrtk 时, k / i <= sqrtk 。所以我们就可以枚举 k / i ,即枚举 [1, sqrtk] 的每一个数字。

   那么,对于我们枚举的每一个数字 x ,以它为 k / i 的 i 一定是连续的一段,它们的和可以用等差数列求和公式算出。

于是就很明确了。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
 
using namespace std;
 
int n, k, SQRTK, L, R;
 
typedef long long LL;
 
LL Ans;
 
int main()
{
    scanf("%d%d", &n, &k);
    Ans = 0ll;
    if (n > k) Ans += (LL)(n - k) * k;
    n = n > k ? k : n;
    SQRTK = sqrt(k * 1.0);
    for (int i = 1; i <= SQRTK; i++) {
        if (i > n) break;
        Ans += (LL)k % i;
    }
    for (int i = 1; i <= SQRTK; i++) {
        L = (k / (i + 1)) + 1; L = L <= SQRTK ? SQRTK + 1: L;
        R = k / i; R = R > n ? n : R;
        if (R < L) continue;
        Ans += (LL)(R - L + 1) * ((k % L) + (k % R)) >> 1;
    }
    printf("%lld
", Ans);
    return 0;
}

  

原文地址:https://www.cnblogs.com/JoeFan/p/4251985.html