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=1⌊ni⌋×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; }
参考链接:https://blog.csdn.net/xigongdali/article/details/82313658