题意:
给出n(n<=2∗106)n(n<=2∗106),求
∑ni=1∑nj=1ϕ(gcd(ϕ(i),ϕ(j)))∑i=1n∑j=1nϕ(gcd(ϕ(i),ϕ(j)))的值。
分析:
看到这种题显然想反演了。
ans=∑i=1n∑j=1nϕ(gcd(ϕ(i),ϕ(j)))ans=∑i=1n∑j=1nϕ(gcd(ϕ(i),ϕ(j)))
=∑D=1nϕ(D)∑i=1n∑j=1n[gcd(ϕ(i),ϕ(j))==D]=∑D=1nϕ(D)∑i=1n∑j=1n[gcd(ϕ(i),ϕ(j))==D]
然后我们枚举ϕ(i)ϕ(i)与ϕ(j)ϕ(j),我们设ad=∑ni=1[ϕ(i)==d]ad=∑i=1n[ϕ(i)==d],x=phi(i)x=phi(i),y=phi(j)y=phi(j),其实可以理解为换元,则原式可以变为,
=∑D=1nϕ(D)∑x=1n∑y=1n[gcd(x,y)==D]∗ax∗ay=∑D=1nϕ(D)∑x=1n∑y=1n[gcd(x,y)==D]∗ax∗ay
然后就是很显然的反演了,我们设sumi=∑i|tatsumi=∑i|tat,
=∑D=1nϕ(D)∑d=1nμ(d)∗(sumD∗d)2=∑D=1nϕ(D)∑d=1nμ(d)∗(sumD∗d)2
设T=DdT=Dd,则
=∑T=1n(sumT)2∑d|Tμ(d)∗ϕ(T/d)=∑T=1n(sumT)2∑d|Tμ(d)∗ϕ(T/d)
设f(i)=∑d|iμ(d)∗ϕ(i/d)f(i)=∑d|iμ(d)∗ϕ(i/d),是个狄利克雷卷积,一定是个积性函数,直接可以上线筛。对于x=pkx=pk,则f(x)=ϕ(x)−ϕ(x/p)f(x)=ϕ(x)−ϕ(x/p)。这个sumsum可以枚举倍数解决,复杂度O(nlogn)O(nlogn)的。其实排序询问可以节约时间,不过暴力也可以过。直接强行清空跑sumsum就好。
代码:
#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);
}
}