まず、区間 [1..b] 間のすべての約数の合計を求めます。
結果は次と等しくなります
[1..b] 間のすべての約数の合計 - [1..a-1] 間の約数の合計
明らかに、これら 2 つの問題は同じ性質のものであり、正しいエンドポイントが異なるだけです。
明らかに、1 から N までの数値の場合、約数の範囲も 1 から N の範囲内になります。
したがって、近似数 L を列挙できます。 もちろん、この列挙は for ループの列挙にはできませんが、上記の質問のように「ジャンプ」しています。
したがって、N/L は、1 ~ N の間で L の倍数がいくつあるかを表し、L はその約数でもある必要があります。
例えば、L=7、N=20の場合
N/20=2 は、1 ~ 20 の範囲内に 7 の倍数である 2 つの数値があることを示します。これらは 7 と 14 として簡単にわかります。これは、7 と 14 の約数の合計を計算するときに、7 を数えなければならないことを意味します。 。
このアルゴリズムの賢さは次のとおりです。
L=8,9,10の場合、N/L=2
したがって、このセクションでは L=7、R=10
したがって、このセクションの約数の合計は 2*7+2*8+2*9+2*10=2*(7+8+9+10)=2*(7+10)*(10-7) となります。 + 1)/2
このセクションを数えた後、L=R+1=10+1=11 と設定します。
11 はおおよその数字として使用されており、1 回しか出現しないことがわかります。
同時に、このセクションの 12、13、14....20 というおおよその数字は 1 回しか出現しないこともわかります。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m;
ll f(ll x)
{
ll l = 1,r = 0,k = 0,ans = 0,m = 0;
while(l <= x)
{
r = x / (x / l);
k = x / l;
ans += k * (l + r) * (r - l + 1) / 2;
l = r + 1;
}
return ans;
}
signed main()
{
cin>>n>>m;
cout<<f(m) - f(n - 1);
return 0;
}