传送门
本题是让求这样一个式子:
∑
i
=
1
n
d
(
i
2
)
\mathbf{\sum_{i=1}^nd(i^2)}
∑i=1nd(i2)。
先看
d
(
n
2
)
\mathbf{d(n^2)}
d(n2)如何化解,根据基础数论学习笔记(下)第十部分6.13和14我们可以知道
d
(
n
2
)
=
∑
d
′
∣
n
∑
k
∣
d
′
∣
μ
(
k
)
∣
\mathbf{d(n^2)=\sum_{d'\mid n}\sum_{k\mid d'}|\mu(k)|}
d(n2)=∑d′∣n∑k∣d′∣μ(k)∣。方便起见假设
f
(
n
)
=
∣
μ
(
n
)
∣
\mathbf{f(n)=|\mu(n)|}
f(n)=∣μ(n)∣,于是有
d
(
n
2
)
=
(
(
f
∗
I
)
∗
I
)
(
n
)
=
(
f
∗
(
I
∗
I
)
)
(
n
)
=
(
f
∗
d
)
(
n
)
=
∑
d
′
∣
n
f
(
d
′
)
d
(
n
d
′
)
\mathbf{d(n^2)=((f*I)*I)(n)=(f*(I*I))(n)=(f*d)(n)=\sum_{d'\mid n}f(d')d(\frac n{d'})}
d(n2)=((f∗I)∗I)(n)=(f∗(I∗I))(n)=(f∗d)(n)=∑d′∣nf(d′)d(d′n)。
代入原式我们可以得到:
∑
i
=
1
n
d
(
i
2
)
=
∑
i
=
1
n
∑
d
′
∣
i
f
(
d
′
)
d
(
i
d
′
)
=
∑
d
′
=
1
n
f
(
d
′
)
∑
i
=
1
⌊
n
d
′
⌋
d
(
i
)
\mathbf{\begin{aligned} \sum_{i=1}^nd(i^2)&=\sum_{i=1}^n\sum_{d'\mid i}f(d')d(\frac i{d'})\\ &=\sum_{d'=1}^nf(d')\sum_{i=1}^{\lfloor\frac n{d'}\rfloor}d(i) \end{aligned}}
i=1∑nd(i2)=i=1∑nd′∣i∑f(d′)d(d′i)=d′=1∑nf(d′)i=1∑⌊d′n⌋d(i)
考虑如何求解
f
(
i
)
\mathbf{f(i)}
f(i)前缀和,显然
∑
i
=
1
n
f
(
i
)
=
∑
i
=
1
n
∣
μ
(
i
)
∣
\mathbf{\sum_{i=1}^nf(i)=\sum_{i=1}^n|\mu(i)|}
∑i=1nf(i)=∑i=1n∣μ(i)∣这个式子表示的实际意义是小于等于n的无平方因子数的个数。因此我们可以利用容斥原理写成
∑
i
=
1
⌊
n
⌋
μ
(
i
)
⌊
n
i
2
⌋
\mathbf{\sum_{i=1}^{\lfloor \sqrt n\rfloor}\mu(i)\lfloor \frac n{i^2}\rfloor}
∑i=1⌊n⌋μ(i)⌊i2n⌋,具体证明见基础数论学习笔记(下)6.15,这个式子可以暴力计算,复杂度是
O
(
n
)
\mathbf{O(\sqrt n)}
O(n)。
然后我们再考虑
d
(
i
)
\mathbf{d(i)}
d(i)的前缀和,显然有
∑
i
=
1
n
d
(
i
)
=
∑
i
=
1
n
∑
d
′
∣
i
1
=
∑
i
=
1
n
⌊
n
i
⌋
\mathbf{\sum_{i=1}^nd(i)=\sum_{i=1}^n\sum_{d'\mid i}1=\sum_{i=1}^n\lfloor\frac ni\rfloor}
∑i=1nd(i)=∑i=1n∑d′∣i1=∑i=1n⌊in⌋,这个式子也可以分块求,然后我们就能够分块求出
∑
d
′
=
1
n
f
(
d
′
)
∑
i
=
1
⌊
n
d
′
⌋
d
(
i
)
\mathbf{\sum_{d'=1}^nf(d')\sum_{i=1}^{\lfloor\frac n{d'}\rfloor}d(i)}
∑d′=1nf(d′)∑i=1⌊d′n⌋d(i),也就是最终的答案,然后一个优化使提前预处理出
n
2
3
\mathbf{n^{\frac 23}}
n32以内的
f
与
d
\mathbf{f与d}
f与d的前缀和,这样类比杜教筛的话总复杂度可以达到
O
(
n
2
3
)
\mathbf{O(n^{\frac 23})}
O(n32)。
ul n,d[maxn];
int prim[maxn],tot,summu[maxn],N;
char mu[maxn];
bool flag[maxn];
void init(int n){
mu[1]=1;
d[1]=1;
FOR(i,2,n+1){
if(!flag[i])prim[tot++]=i,mu[i]=-1,d[i]=2,summu[i]=2;
for(register int j = 0;j<tot && prim[j]*i<=n;++j){
flag[i*prim[j]]=1;
if(i%prim[j]==0){
d[i*prim[j]]=d[i]+d[i]/summu[i];
summu[i*prim[j]]=summu[i]+1;
break;
}
mu[i*prim[j]]=-mu[i];
d[i*prim[j]]=2*d[i];
summu[i*prim[j]]=2;
}
}
FOR(i,1,n+1)d[i]+=d[i-1],summu[i]=(summu[i-1]+abs(mu[i]));
}
ul calf(ul n){
if(n<=N)return summu[n];
register int limt=sqrt(n);
register ul ans=0;
for(register ll i=1;i<=limt;++i)ans+=mu[i]*(n/(i*i));
return ans;
}
ul cald(ul n){
if(n<=N)return d[n];
register ul i=1,j,ans=0;
while(i<=n){
j=n/(n/i);
ans+=(j-i+1)*(n/i);
i=j+1;
}
return ans;
}
void solve(){
ul i=1,j,ans=0,pre=0,cur;
while(i<=n){
j=n/(n/i);
ans+=((cur=calf(j))-pre)*cald(n/i);
i=j+1;
pre=cur;
}
wrn(ans);
}
int main(){
int t;
ul mxn=0;
vector<ul>a;
rd(&t);
while(t--){
rd(&n);
mxn=max(mxn,n);
a.push_back(n);
}
N=pow(mxn,2.0/3.0);
if(N<=10000)init(10000);else init(N);
FOR(i,0,a.size()){
n=a[i];
solve();
}
}