51nod 1594 Gcd and Phi
原题链接:
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1594
开始的时候。疯狂寻找:
gcd(φ(i),φ(j))
的性质。
最后得到一个奇怪的东西:
gcd(φ(i),φ(j))=φ(gcd(i,j))f(igcd(i,j))f(jgcd(i,j))
其中,
f
为积性函数,f(Pk)=P−1,f(1)=1
没有用。
也就出去晃荡了一会。
突然想到。本来就是要寻找 gcd 于 (i,j) 有序对的一种直接映射关系,方便应用反演
φ(n)<n
用桶来存储一下每一个 φ(i) 对应对值的数量
那么,令
cnt(k)=∑i=1n[φ(i)=k]
那么
∑i=1n∑j=1nφ(φ(gcd(i,j)))=∑k=1nφ(k)∑i=1n∑j=1n[gcd(i,j)=k]cnt(i)cnt(j)
令:
f(k)=∑i=1n∑j=1n[gcd(i,j)=k]cnt(i)cnt(j)F(k)=∑k|df(d)
则:
F(k)=∑k|i,k≤n∑k|j,j≤ncnt(i)cnt(j)=(∑k|i,i≤ncnt(i))2
F
可以通过预处理得到。
f(k)=∑k|dμ(dk)F(d)
answer=∑k=1nφ(k)∑k|dμ(dk)F(d)
总时间复杂度 O(nlogn)
#include <algorithm>
#include <string.h>
#include <stdio.h>
#define MAXN 2000002
using namespace std;
typedef long long LL;
int phi[MAXN],minDiv[MAXN],sum[MAXN];
int cnt[MAXN];
int F[MAXN];
bool vis[MAXN];
int prime[MAXN],mu[MAXN];
void init(int n=MAXN)
{
int cnt=0;
for(int i=1;i<n;i++) minDiv[i]=i;
for(int i=2;i*i<n;i++)
{
if(minDiv[i]==i)
{
for(int j=i*i;j<n;j+=i)
{
minDiv[j]=i;
}
}
}
phi[1]=mu[1]=1;
for(int i=2;i<n;i++)
{
phi[i]=phi[i/minDiv[i]];
if((i/minDiv[i])%minDiv[i]==0)
phi[i]*=minDiv[i];
else
phi[i]*=minDiv[i]-1;
if(!vis[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
mu[i*prime[j]]=-mu[i];
}
}
}
int main ()
{
init();
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
n++;
memset(cnt,0,(n+1)*sizeof(int));
for(int i=1;i<n;i++) cnt[phi[i]]++;
for(int i=1;i<n;i++)
{
F[i]=0;
for(int j=i;j<n;j+=i) F[i]+=cnt[j];
}
LL ans=0;
for(int k=1;k<n;k++)
{
if(F[k]<1)continue;
LL u=0;
for(int d=k,t=1;d<n;d+=k,t++) u+=(LL)mu[t]*F[d]*F[d];
ans+=phi[k]*u;
}
printf("%lld\n",ans);
}
return 0;
}