zoukankan      html  css  js  c++  java
  • codevs 2606 约数和问题 (数学+分块)

    题目描述 Description

    Smart最近沉迷于对约数的研究中。

    对于一个数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算出这个值吗?

    输入描述 Input Description

    输入文件仅一行,两个正整数X和Y(X<Y),表示需要计算f(X)+f(X+1)+……+f(Y)。

    输出描述 Output Description

    输出只有一行,为f(X)+f(X+1)+……+f(Y)的值。

    样例输入 Sample Input

    2 4

    样例输出 Sample Output

    14

    数据范围及提示 Data Size & Hint

    对于20%的数据有1≤X<Y≤10^5。

    对于60%的数据有1≤X<Y≤1*10^7。

    对于100%的数据有1≤X<Y≤2*10^9。

    思路:

    这道题代码很简单,主要难点是推公式,我们先可以先推出: ans = ∑⌊n/i⌋*i (1<=i<=n,向下取整),解释下这个公式,我们是取1-n的约数和,那么 n/i向下取整也就是1-n中所有可以整除i的数的个数,然后再乘上i就是i这个约数对答案的贡献,i从1-n跑一边便可以算出答案,但是这样会超时的,那么我们需要优化下这个公式,因为是向下去整的那么肯定会有一些连续的数除i后向下取整得到的值一样,我们可以求出这些值的左右边界,将其归为一块,因为⌊n/i⌋(1<=i<=n,)的值一定递增的等差数列,那么我们求出每一个块的左右边界,直接套用等差数列的求和公式,(a1+an)*n/2, 带入l,r就是: (l+r)*(r-l+1)/2,这样就求的了个数之后再乘上权值就好了。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    ll solve(ll x){
        if(x == 1||x == 0) return x;
        ll l = 1,r = 0,ans = 0; //左右边界
        while(l <= x){
            r = x/(x/l); 
            ans += (x/l)*(l+r)*(r-l+1)/2;
            l = r+1;
        }
        return ans;
    }
    
    int main()
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        cout<<solve(y) - solve(x-1)<<endl;
    }

    实现代码:

  • 相关阅读:
    MARK--2020年第一次事故
    MySQL MHA--基于Python实现GTID模式的主从切换
    MySQL Replication--复制延迟排查
    MySQL InnoDB Engine--多版本一致性视图(MVCC)
    MySQL InnoDB Engine--数据页存储和UPDATE操作 2
    MySQL InnoDB Engine--数据页存储和UPDATE操作
    Semantic UI基础使用教程
    sqlserver 批量修改数据库表主键名称为PK_表名
    navicate premium连接sqlserver时报08001错误的解决方法
    checklistbox的使用
  • 原文地址:https://www.cnblogs.com/kls123/p/9943959.html
Copyright © 2011-2022 走看看