Gym 101652P:Fear Factoring 数论

 

Problem Description:

 

这里写图片描述这里写图片描述

  题目描述:

      函数f(X)f(X)表示XX所有约数的和。例如:f(6)=1+2+3+6=12f(6)=1+2+3+6=12。

      给你XX和YY,求f(X)+f(X+1)++f(Y)f(X)+f(X+1)+……+f(Y)的值. 

  Solution:

  ans=ni=1ni×ians=∑i=1n⌊ni⌋×i.

  简单来说:

  除法分块:

  区块值 区块始末

  举个例子 :12 

  次数是有12/n算出来的  像当n==5时 12/5==2,也就是说5出现了两次

   [1]:12次      [2] :6次     [3] : 4次   [4] :3次  

  [5]: 2次          [6]:   2次     [7] : 1次   [8]: 1次

  [9]: 1次          [10] :1次     [11] :1次   [12] 1 次

  left是当前区块的开始 ,right 是当前区块的终点

  区块是按出现次数分的,像出现次数为12次 分一个区块 ,这个区块有1个元素 :1

                                             出现次数为6次  分一个区块,   这个区块有1个元素 :2

                                             出现次数为4次 分一个区块,   这个区块有1元素 :   3

                                            出现次数为3次 分一个区块 ,   这个区块有1个元素    4

                                            出现次数为2次 分一个区块,   这个区块有2个元素     5 6

                                            出现次数为1次,分一个区块 ,这个区块有6个元素:7 8 9 10 11 12

  可以发现两个规律:

  1: 越小的数分在区块值大的区块

  2:  同一区块内的元素是按等差序列分布的。

  可以按开始元素小的开始枚举

  left是区块的开始元素,right是区块的结束元素

  n/left 该区块的值

  区块值也就是区块内的元素总共出现的次数

  AC_Code:

  

#include<iostream>
#include<cstdio>
using namespace std;
unsigned long long get_sum(unsigned long long n)
{
  unsigned long long ans=0;
  unsigned long long left,right;
  for(left=1;left<=n;left=right+1)
  {
    right=n/(n/left);
    ans += (n/left)*(left+right)*(right-left+1)/2;  
    //这里用的是等差数列 left是首项,right是末项
  }
  return ans;
}
int main()
{
    unsigned long long a,b;
    scanf("%llu%llu", &a, &b);
    printf("%llu\n", get_sum(b)-get_sum(a-1));
    return 0;
}
 
View Code

  

  参考链接:https://blog.csdn.net/xigongdali/article/details/82313658

原文地址:https://www.cnblogs.com/syycjh/p/9682893.html