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