舒阳 的博客

舒阳 的博客

QAQ QWQ

题解 P2424 【约数和】

posted on 2019-10-23 00:40:25 | under 题解 |

基本思路

题目要求计算:

$$f(x) + f(x + 1) + f(x + 2) ... f(y - 1) + f(y)$$

再加上求单个函数并不好算,反而对于此函数来说,求前缀和会更为方便。

设:

$$S(n) = \sum f(n)$$

那么:

数字$1$会对答案贡献$\frac{x}{1}$次,即:$\lfloor \frac{x}{1} \rfloor \times 1$

数字$2$会对答案贡献$\frac{x}{2}$次,即:$\lfloor \frac{x}{2} \rfloor \times 2$

数字$3$会对答案贡献$\frac{x}{3}$次,即:$\lfloor \frac{x}{3} \rfloor \times 3$

所以:

$$S(n) = \sum(\lfloor \frac{n}{i} \rfloor \times i)$$

可以$O(n)$求出$S(n)$

代码I

signed main()
{
    int x = read() - 1, y = read();
    if(x < 0) x = 0;
    int ans1 = 0, ans2 = 0;
    for(_R int i = 1;i <= y;i++)
        ans1 += (y / i) * i;
    for(_R int i = 1;i <= x;i++)
        ans2 += (x / i) * i;
    printf("%lld", ans1 - ans2);
    return 0;
}

不能拿到满分。

优化

观察这个式子:

$$(x / i) * i$$

注意到$\lfloor \frac{x}{i} \rfloor$随着$i$的增长并不是一直在变化的,而是分段的。

形式化的讲,

$$g(i) = \lfloor \frac{x}{i} \rfloor$$

这个函数是单调呈现阶梯状递增的。

只要求出这个阶梯状函数的拐角,两拐角之间的平台可以设为常熟$k$。

那么在某段区间内,算式能变成

$$k \times i$$

利用等差数列求和即可。

现在的关键在于找到$\lfloor \frac{x}{i} \rfloor$发生改变的拐点。

由于我太菜了,我不能直接算出来,但是比较好想的就是,因为函数$g(i)$是单调的,所以可以二分拐点。

代码II

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define _R register
#define int long long 
using namespace std;
int x, y;
long long SolveSegment(const int L,const int R,const int Val)
{
    return (((L + R) * 1LL * (R - L + 1LL)) / 2LL) * 1LL * Val;
}
long long GetIt(int x)
{
    if(x <= 0) return 0LL;
    if(x == 1) return 1LL;
    long long res = 0;
    for(_R int i = 1;i < x;){
        int now = x / i;
        int L = i;
        int R = x;
        int ans;
        if(now == 1){
            res += SolveSegment(ans, x, 1);
            break;
        }
        while(L < R)
        {
            int mid = (L + R) >> 1;
            if((x / mid) < now) ans = mid, R = mid;
            else L = mid + 1;
        }
        res += SolveSegment(i, ans - 1, x / i);
        i = ans;
    }
    return res;
}
signed main()
{
    cin >> x >> y;
    long long ans =  GetIt(y) - GetIt(x - 1);
    printf("%lld",ans);
    return 0;
}

本文目的在于提供一种笔者感觉比较好想的思路,但是感觉既然做到这道题了,就尽量去看看更高级的做法?

By Shu_Yu_Mo