• 洛谷 2424 约数和


    题目:https://www.luogu.org/problemnew/show/P2424
    题意:
    对于一个数X,函数f(X)表示X所有约数的和。例如:f(6)=1+2+3+6=12。对于一个X,Smart可以很快的算出f(X)。现在的问题是,给定两个正整数X,Y(X<Y),Smart希望尽快地算出f(X)+f(X+1)+……+f(Y)的值,你能帮助Smart算出这个值吗?
    解法:
    数学真是玄学...顺便说一句博客园的数学公式编辑真的垃圾
    把f(n)用数学方式表达一下 $sum_{d|x} d$
     那么ans =$sum_{i=a}^b f(i)$ = $sum_{i=a}^b sum_{d|x} d$,然后直接枚举并累加,但是这样会TLE。
    可以考虑枚举约数,考虑1~n中有几个数是d的倍数,如果有,可以表示为k*d。易知1<=k*d<=n,所以1<=k<=[n/d]。
    也就是说把1~n中所有d的倍数拿出来,有d,2d,3d,......,[n/d]d,所以1~n中d的倍数有[n/d]个
     先求b的个数,然后减去a-1的个数,就是b-a的个数了。这样,$sum_{i=a}^b f(i)$ = $sum_{i=a}^b [n/i]*i$,那么ans = $sum_{i=1}^b [b/i]*i$ - $sum_{i=1}^{a-1} [{a-1}/i]*i$
    这样做的时间复杂度为O(b),仍然会TLE。
    再看$sum_{i=1}^n [n/i]*i$,只看[n/i],以12为例,列出来是12,6,4,3,2,2,1,1,1,1,1,1,第i个数表示[n/i]的值,这个序列表示的就是每个因数的“贡献”,1贡献12次,2贡献6次......
    有些数出现了重复,考虑用区间将这些重复的值一次性算出来。设区间左右端点,L,R,L就是上一个R+1,L初始值为1,R = n/(n/i),(n/i)就是约数,如果不知道为什么,那就再看一遍“1~n中有几个数是 d 的倍数”。
    ans+=约数*约数的个数,约数=n/L,约数个数$sum_{i=L}^R i$,用等差数列求和公式表示一下就是(L+R)∗(R−L+1)/2
    即ans+=(n/L)∗(L+R)∗(R−L+1)/2

    AC:

    #include <iostream>
    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 a,b;
        cin >> a >> b;
        cout << sum(b)-sum(a-1) <<endl;
        return 0;
    }


     

  • 相关阅读:
    WPF 组织机构摄像机树 全量加载 大数据量 分页加载摄像机节点
    vue3 自定义指令(简易版防抖、节流)
    测试Writer
    The blog In The cnblogs!
    分割
    coeLmiGMmW
    js 之 setTimeout 0 分析
    vue 组件 之 注册 及 组件内data的使用
    Js/es for(let i in Obj)效率分析及优化
    vue.js 表单控件 输入绑定 vmodel的使用
  • 原文地址:https://www.cnblogs.com/zz990728/p/8943505.html
Copyright © 2020-2023  润新知