The Slivians are afraid of factoring; it's just, well, difficult.
Really, they don't even care about the factors themselves, just how much they sum to.
We can define F(n)F(n) as the sum of all of the factors of nn; so F(6) = 12F(6)=12 and F(12) = 28F(12)=28. Your task is, given two integers aa and bb with a ≤ ba≤b, to calculate S = \sum_{a≤n≤b} F(n)S=∑a≤n≤bF(n).
1 Input
The input consists of a single line containing space-separated integers aa and bb (1 ≤ a ≤ b ≤ 10^{12}; b-a ≤ 10^{6} )(1≤a≤b≤1012;b−a≤106).
2 Output
Print SS on a single line.
样例输入复制
101 101 28 28 1 10 987654456799 987654456799 963761198400 963761198400 5260013877 5260489265
样例输出复制
102 56 87 987654456800 5531765944320 4113430571304040
https://www.it610.com/article/1289920140560900096.htm(大佬讲的好)
显然是要枚举因子算贡献,
然后要搞前缀和算[1,r]-[1,l-1]
两种做法,
一个是这次要学的援引的博主的做法……
另一个是自己瞎搞搞出来的,先枚举数出现的次数,再枚举数的值,两个1e6能摊出来
可以看出,一段区间的出现次数都是相同的,那我们不妨枚举区间
这个区间的段数不会超过1e6
比如对于n=10,可分成这些段[1][2][3][4,5][6,10]
分别出现10次,5次,3次,2次,1次
那么,对于当前端点l,l出现了n/l次,
而同样出现n/l次的数,最大为r=n/(n/l),
这个向下取整的操作真的惊艳啊
那么对于[l,r]这段区间的数都出现了n/l次,
其贡献为(l+r)*(r-l+1)/2*(n/l),
然后令l=r+1,去统计下一段区间的贡献即可
# include <iostream>
# include <algorithm>
# include <cstring>
# include <math.h>
# include <stdio.h>
# include <vector>
# include <map>
using namespace std;
# define ll long long
# define ull unsigned long long
ull get(ull n){
ull r;
ull ans = 0;
for(ull l = 1; l <= n; l = r+1){
r = n/(n/l);
ans += (l+r)*(r-l+1)*(n/l)/2;
}
return ans;
}
int main(){
ull a,b;
while(cin >> a >> b){
cout << get(b) - get(a-1) << endl;
}
return 0;
}