题面
题目要我们求
∑i=1n∑d|iμ(d)∗σ20(id)
设 f(i)=∑d|iμ(d)∗σ20(id) ,感觉 f 会是个很优美的东西,打表发现
怎么证明呢?考虑 σ0(i2)=∑d|iμ(d)∗σ20(id) 用莫比乌斯反演反过来就是 σ20(n)=∑d|nσ0(n2) 。这里给出一种推式子的证法:
∑d|nσ0(d2)=∑d|n∑i|d∑j|d[(i,j)=1]=∑d|n∑i|d∑j|d[(i∗⌊nd⌋,j∗⌊nd⌋)=⌊nd⌋]
=∑d|n∑i|n∑j|n[(i,j)=⌊nd⌋]=∑d|n∑i|n∑j|n[(i,j)=d]
其中第一步利用了 σ0(n2) 等于 n 的有序互质约数对个数,大概考虑
σ20(n)=∑i|n∑j|n1=∑d|n∑i|n∑j|n[(i,j)=d]
得证。
然后就和 SPOJ DIVCNT2一样了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=1000000;
int n,pri[maxn+5],num,mu[maxn+5],d[maxn+5],sm[maxn+5],sd[maxn+5];
bool flag[maxn+5];
void getpri(int n)
{
memset(flag,1,sizeof(flag));
flag[1]=0;mu[1]=1;
for(int i=2;i<=n;i++)
{
if(flag[i]) pri[++num]=i,mu[i]=-1;
for(int j=1;j<=num&&i*pri[j]<=n;j++)
{
flag[i*pri[j]]=0;
if(i%pri[j]==0) {mu[i*pri[j]]=0;break;}
mu[i*pri[j]]=-mu[i];
}
}
}
ll qsd(int m)
{
if(m<=maxn) return sd[m];
ll re=0;
for(int l=1,r=1,k;l<=m;l=r+1)
{
k=m/l;r=m/k;
re+=(ll)(r-l+1)*k;
}
return re;
}
ll qsm(int m)
{
if(m<=maxn) return sm[m];
int gen=round(sqrt(m)+1);ll re=0;
for(int i=1;i<=gen;i++)
re+=mu[i]*(m/(i*i));
return re;
}
ll solve()
{
ll re=0;
for(int l=1,r=1,k;l<=n;l=r+1)
{
k=n/l;r=n/k;
re+=qsd(k)*(qsm(r)-qsm(l-1));
}
return re;
}
int main()
{
int ca;
scanf("%d",&ca);
getpri(maxn);
for(int i=1;i<=maxn;i++)
for(int j=1;i*j<=maxn;j++)
d[i*j]++;
for(int i=1;i<=maxn;i++)
sm[i]=sm[i-1]+mu[i]*mu[i],sd[i]=sd[i-1]+d[i];
while(ca--)
{
scanf("%d",&n);
printf("%lld\n",solve());
}
return 0;
}