zoukankan      html  css  js  c++  java
  • 洛谷 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;
    }


     

  • 相关阅读:
    2014年辛星完全解读Javascript第六节 对象
    2014年辛星完全解读Javascript第五节 break和continue与错误处理
    2014年辛星完全解读Javascript第四节 流程控制语句
    2014年辛星完全解读Javascript第三节
    移动端滑动卡顿问题
    移动端iOS阻止橡皮筋效果
    inline-block 元素之间的空白问题
    初识webview
    原型链、prototype、_proto_那些事
    VMware workstation转到vsphere解决办法
  • 原文地址:https://www.cnblogs.com/zz990728/p/8943505.html
Copyright © 2011-2022 走看看