タイトルは非常に簡潔ですが、朝の反転時には何もする必要はありません。
nlnを直接実行すると、元の形式を変換できます= \(\ sum_ {x = 1} ^ n \ frac {n} {x} d(x)\)
このように、dは生産関数の直接関数であるため、O(n)メソッドがあります。ブロックを直接分割する必要はありませんO(n)。
const int MAXN=15000010;
int n,top;
int v[MAXN],g[MAXN],p[1000010],d[MAXN];
inline void prepare()
{
d[1]=1;
rep(2,n,i)
{
if(!v[i])
{
p[++top]=g[i]=v[i]=i;
ll sum=p[top];int j=1;
while(sum<=n)d[sum]=j+1,sum=sum*p[top],++j;
}
rep(1,top,j)
{
if(n/i<p[j])break;
int ww=i*p[j];
v[ww]=p[j];
if(p[j]==v[i])
{
g[ww]=g[i]*p[j];
d[ww]=d[i/g[i]]*d[g[ww]];
break;
}
d[ww]=d[i]*d[p[j]];
g[ww]=p[j];
}
}
}
int main()
{
//freopen("divisor.in","r",stdin);
//freopen("divisor.out","w",stdout);
get(n);
if(n<=15000000)
{
prepare();//put(top);
//rep(1,n,i)put(d[i]);
ll sum=0;
rep(1,n,i)sum=sum+(ll)(n/i)*d[i];
putl(sum);
}
return 0;
}
自閉症になるためにここを押してください。
D関数のプレフィックスとしないデュの教示画面もGCD物は、以下のように置換されていてもよい(D(I)= \ \ sum_ {X = 1} ^ {I} [(X、I)= X] \) この事単純化するのは役に立たないか困難です。
もう1つ\(d(xy)= \ sum_ {i | x} ^ {x} \ sum_ {j | y} ^ {y} [(i、j)= 1] \)
この質問とは何の関係もありません。
この質問ができる理由は、それが接頭辞と特異性の問題だからです。
\(d(w)= \ sum_ {x | w} 1 \)これを観察すると、\(x、\ frac {w} {x} \)は2タプルであることがわかります。
そして、\(\ sum_ {i = 1} ^ n \ sum_ {p | i} d(p)\)は、これがi \(\ frac {i} {p}、d(p)\ )、すなわち、\(\ FRAC {I} { P}、\ FRAC {X} {W}、X \)
このトリプルは1を貢献します。
xyz <= nなどのすべてのトリプレットがカウントされることがわかります。
そして、このトリプルは、数iに存在する唯一のものです。
设x <= y <= z。若x <= \(n ^ {\ frac {1} {3}}、y \ leq \ sqrt(\ frac {n} {x})\)
x、yを列挙してzの数をカウントします。
x、y、zは順列になる可能性があるため、6を掛けます。
ただし、上記のトリプルの状況を観察すると、x == yの場合、この状況は整理されていないため、対応する回数を減算することは同じです。
非常に良い質問です。複雑さは\(n ^ {\ frac {2} {3}} \)に近いです(私はそれを証明しません。
const ll MAXN=100010;
ll n;
int main()
{
freopen("divisor.in","r",stdin);
freopen("divisor.out","w",stdout);
get(n);
ll w1=1,w2=1,ans=0;
while(w1*w1*w1<=n)++w1;--w1;
while(pf(w2)<=n)++w2;--w2;
for(ll i=1;i<=w1;++i)
{
ll ww=n/i;
for(ll j=i;j*j<=ww;++j)ans+=ww/j-j+1;
}
ll cnt=0;
for(ll i=1;i<=w2;++i)cnt+=n/i/i;
putl(ans*6-cnt*3-2*w1);
return 0;
}