借鉴:https://blog.csdn.net/qq_39599067/article/details/81807580
无法估计他的值时最好用无符号的long long
除法分块:
区块值 区块始末
举个例子 :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 该区块的值
区块值也就是区块内的元素总共出现的次数
#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;
}