1 条题解

  • 0
    @ 2025-8-24 21:37:33

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zzlzk
    **

    搬运于2025-08-24 21:37:33,当前版本为作者最后更新于2017-09-22 19:12:58,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    • f(x)f(x)用数学方式表示一下就是f(x)=dxdf(x)=\sum\limits_{d|x}d

    • 那 $ans=\sum\limits_{i=x}^{y}f(i)=\sum\limits_{i=x}^{y}\sum\limits_{d|i}d$

    • 那我们就可以直接枚举然后累加就可以了。

    • 但这样的时间复杂度是O(i=xyi)O(\sum\limits_{i=x}^{y}\sqrt i),会TLETLE

    • 所以换一种思路,枚举约数

    • 考虑1n1-n中有几个数是 dd 的倍数

    • 假如1n1-n中存在 dd 的倍数,那这个数肯定可以表示为 kd(kN+)k·d(k\in N_+)

    • kk 的范围可以再简化一下,$1\leq k·d\leq n\Rightarrow 1 \leq k \leq \lfloor\frac{n}{d}\rfloor$

    • 也就是说从1n1-n 中把 dd 的倍数单独拿出来,那就是d,2d,3d.....nddd,2d,3d.....\lfloor\frac{n}{d}\rfloor d

    • 所以1n1-ndd 的倍数的个数就是 nd\lfloor\frac{n}{d}\rfloor

    • 求出 yy 的个数,再减去 x1x-1 的个数,也就是xyx-y 的个数,这个是比较好想的,所以我就不详细说了。

    • 这样i=1nf(i)\sum\limits_{i=1}^{n}f(i)就可以表示为i=1n(nii)\sum\limits_{i=1}^{n}(\lfloor\frac{n}{i}\rfloor*i)

    • 那$ans=\sum\limits_{i=1}^{y}(\lfloor\frac{y}{i}\rfloor*i)-\sum\limits_{i=1}^{x-1}(\lfloor\frac{x-1}{i}\rfloor*i)$

    • 这种做法时间复杂度是O(y)O(y),还是会TLETLE

    • 再看i=1n(nii)\sum\limits_{i=1}^{n}(\lfloor\frac{n}{i}\rfloor*i)

    • 只看ni\lfloor\frac{n}{i}\rfloor,胡乱找个数列出来ni(1in)\lfloor\frac{n}{i}\rfloor(1\leq i \leq n)的值

    • 1212为例,列出来是12,6,4,3,2,2,1,1,1,1,1,112,6,4,3,2,2,1,1,1,1,1,1 ,第 ii 个数表示ni\lfloor\frac{n}{i}\rfloor的值

    • 发现这里面有些数是重复的,考虑能不能把这些重复的一次算出来

    • 把那些相同的值用区间来表示,那只要求出左右端点l,rl,r来就好了

    • ll 比较好求,观察上面的数列,ll 就是上一个rr11,初始l=1l=1

    • rr 怎么求呢?其实很简单

    • r=n/(n/l)r=n/(n/l)

    • ll是那个数列的下标,所以 (n/l)(n/l) 就是约数,那 rr 就显然了,如果不知道为什么,那就再看一遍“1n1-n中有几个数是 dd 的倍数”。

    • llrr 都知道了, 那答案呢?

    • ans+=ans+=约数*约数的个数

    • 约数=n/l=n/l

    • 约数的个数=i=lri=\sum\limits_{i=l}^r i,用等差数列求和公式表示一下就是(l+r)(rl+1)/2(l+r)*(r-l+1)/2

    • ans+=(n/l)(l+r)(rl+1)/2ans+=(n/l)*(l+r)*(r-l+1)/2

    • 然后就愉快的AC啦!


    比题解不知道短到那里去的代码

    #include<cstdio>
    using namespace std;
    typedef long long ll;
    
    ll sum(int n) {
        if(n<=1) return n;
        ll ans=0;
        for(ll l=1,r;l<=n;l=r+1) {
            r=n/(n/l);
            ans+=(n/l)*(l+r)*(r-l+1)/2;
        }
        return ans;
    }
    
    int main() {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%lld\n",sum(y)-sum(x-1));
        return 0;
    }
    
    • 1

    信息

    ID
    1451
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者