题意
给一棵n个节点的数,点权为1到n的整数且互不相同。求
∑
i
=
̸
j
φ
(
v
a
l
i
∗
v
a
l
j
)
∗
d
i
s
(
i
,
j
)
n
∗
(
n
−
1
)
\frac{\sum_{i=\not j}\varphi(val_i*val_j)*dis(i,j)}{n*(n-1)}
n∗(n−1)∑i≠jφ(vali∗valj)∗dis(i,j)
n
≤
2
∗
1
0
5
n\le2*10^5
n≤2∗105
分析
注意到
φ
(
a
b
)
=
φ
(
a
)
∗
φ
(
b
)
∗
g
c
d
(
a
,
b
)
φ
(
g
c
d
(
a
,
b
)
)
\varphi(ab)=\frac{\varphi(a)*\varphi(b)*gcd(a,b)}{\varphi(gcd(a,b))}
φ(ab)=φ(gcd(a,b))φ(a)∗φ(b)∗gcd(a,b)
枚举
v
a
l
i
val_i
vali和
v
a
l
j
val_j
valj的最大公约数
d
d
d,设
f
d
=
∑
g
c
d
(
v
a
l
i
,
v
a
l
j
)
=
d
φ
(
v
a
l
i
)
∗
φ
(
v
a
l
j
)
∗
d
i
s
(
i
,
j
)
f_d=\sum_{gcd(val_i,val_j)=d}\varphi(val_i)*\varphi(val_j)*dis(i,j)
fd=gcd(vali,valj)=d∑φ(vali)∗φ(valj)∗dis(i,j)
那么答案就是
a
n
s
=
∑
d
=
1
n
f
d
∗
d
φ
(
d
)
ans=\sum_{d=1}^n\frac{f_d*d}{\varphi(d)}
ans=d=1∑nφ(d)fd∗d
我们只要求出
g
d
=
∑
d
∣
g
c
d
(
v
a
l
i
,
v
a
l
j
)
φ
(
v
a
l
i
)
∗
φ
(
v
a
l
j
)
∗
d
i
s
(
i
,
j
)
g_d=\sum_{d|gcd(val_i,val_j)}\varphi(val_i)*\varphi(val_j)*dis(i,j)
gd=d∣gcd(vali,valj)∑φ(vali)∗φ(valj)∗dis(i,j)
然后用反演来求
f
d
f_d
fd即可。
求
g
d
g_d
gd可以用点分治或者虚树,加入一个点的时候枚举其约数即可。
时间复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
typedef long long LL;
const int N=200005;
const int MOD=1000000007;
int n,a[N],cnt,last[N],phi[N],mu[N],prime[N],tot,g[N],s1[N],s2[N],f[N],root,sum,size[N],top,stack[N],dep[N];
bool not_prime[N],vis[N];
struct edge{int to,next;}e[N*2];
std::vector<int> vec[N],rub;
int add(int x,int y) {return x+y<MOD?x+y:x+y-MOD;}
int dec(int x,int y) {return x-y<0?x-y+MOD:x-y;}
int mul(int x,int y) {return (LL)x*y%MOD;}
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
void get_prime(int n)
{
mu[1]=phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i]) prime[++tot]=i,phi[i]=i-1,mu[i]=-1;
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
mu[i*prime[j]]=-mu[i];
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
void get_root(int x,int fa)
{
size[x]=1;f[x]=0;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa||vis[e[i].to]) continue;
get_root(e[i].to,x);
size[x]+=size[e[i].to];
f[x]=std::max(f[x],size[e[i].to]);
}
f[x]=std::max(f[x],sum-size[x]);
if (!root||f[x]<f[root]) root=x;
}
void get(int x,int fa)
{
stack[++top]=x;size[x]=1;dep[x]=dep[fa]+1;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa&&!vis[e[i].to]) get(e[i].to,x),size[x]+=size[e[i].to];
}
void solve(int x)
{
vis[x]=1;
for (int i=0;i<vec[a[x]].size();i++) s1[vec[a[x]][i]]=add(s1[vec[a[x]][i]],phi[a[x]]),rub.pb(vec[a[x]][i]);
dep[x]=0;
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]) continue;
top=0;
get(e[i].to,x);
for (int j=1;j<=top;j++)
for (int k=0;k<vec[a[stack[j]]].size();k++)
{
int y=stack[j],p=vec[a[y]][k];
rub.pb(p);
g[p]=add(g[p],mul(phi[a[y]],add(s2[p],mul(s1[p],dep[y]))));
}
for (int j=1;j<=top;j++)
for (int k=0;k<vec[a[stack[j]]].size();k++)
{
int y=stack[j],p=vec[a[y]][k];
rub.pb(p);
s1[p]=add(s1[p],phi[a[y]]);s2[p]=add(s2[p],mul(phi[a[y]],dep[y]));
}
}
for (int i=0;i<rub.size();i++) s1[rub[i]]=s2[rub[i]]=0;
rub.clear();
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]) continue;
root=0;sum=size[e[i].to];
get_root(e[i].to,x);
solve(root);
}
}
int main()
{
scanf("%d",&n);
get_prime(n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j+=i)
vec[j].pb(i);
for (int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
addedge(x,y);
}
sum=n;root=0;
get_root(1,0);
solve(root);
int ans=0;
for (int i=1;i<=n;i++)
{
int s=0;
for (int j=i;j<=n;j+=i) (s+=(LL)g[j]*mu[j/i]%MOD)%=MOD;
(ans+=(LL)s*i%MOD*ksm(phi[i],MOD-2)%MOD)%=MOD;
}
ans=(ans*2%MOD+MOD)%MOD;
printf("%d\n",(LL)ans*ksm((LL)n*(n-1)%MOD,MOD-2)%MOD);
return 0;
}