题意:
给出
,求
的值。
分析:
看到这种题显然想反演了。
然后我们枚举 与 ,我们设 , , ,其实可以理解为换元,则原式可以变为,
然后就是很显然的反演了,我们设 ,
设 ,则
设 ,是个狄利克雷卷积,一定是个积性函数,直接可以上线筛。对于 ,则 。这个 可以枚举倍数解决,复杂度 的。其实排序询问可以节约时间,不过暴力也可以过。直接强行清空跑 就好。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define LL long long
const int maxn=2e6+7;
using namespace std;
LL phi[maxn],f[maxn],sum[maxn],a[maxn];
LL not_prime[maxn],prime[maxn],low[maxn];
LL n,cnt,T;
void getf(LL n)
{
phi[1]=1;
f[1]=1;
for (LL i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
phi[i]=i-1;
f[i]=phi[i]-phi[1];
low[i]=i;
}
for (LL j=1;j<=cnt;j++)
{
if (i*prime[j]>n) break;
not_prime[i*prime[j]]=1;
if (low[i]%prime[j]==0) low[i*prime[j]]=low[i]*prime[j];
else low[i*prime[j]]=prime[j];
if (i*prime[j]==low[i*prime[j]])
{
phi[i*prime[j]]=phi[i]*prime[j];
f[i*prime[j]]=phi[i*prime[j]]-phi[i];
}
else
{
LL x=low[i*prime[j]],y=i*prime[j]/x;
f[i*prime[j]]=f[x]*f[y];
phi[i*prime[j]]=phi[x]*phi[y];
}
if (i%prime[j]==0) break;
}
}
}
int main()
{
getf(2e6);
scanf("%lld",&T);
while (T--)
{
scanf("%lld",&n);
LL ans=0;
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
for (LL i=1;i<=n;i++) a[phi[i]]++;
for (LL i=1;i<=n;i++)
{
for (LL j=i;j<=n;j+=i) sum[i]+=a[j];
}
for (LL i=1;i<=n;i++) ans+=sum[i]*sum[i]*f[i];
printf("%lld\n",ans);
}
}