#G. 約数の 6 番目を求める


まず、区間 [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;
}

おすすめ

転載: blog.csdn.net/weq2011/article/details/129191269