problem
给出一个 n n n 个点的树,每个点有一个点权 a i a_i ai,且 a i a_i ai 构成 1 ∼ n 1\sim n 1∼n 的一个排列,求:
1 n ( n − 1 ) ∑ i = 1 n ∑ j = 1 n φ ( a i a j ) × d i s ( i , j ) \frac 1{n(n-1)}\sum_{i=1}^n\sum_{j=1}^n\varphi(a_ia_j)\times \mathrm{dis}(i,j) n(n−1)1i=1∑nj=1∑nφ(aiaj)×dis(i,j)
其中 φ \varphi φ 是欧拉函数, d i s ( i , j ) dis(i,j) dis(i,j) 表示 i , j i,j i,j 两点在树上的距离。答案对 1 0 9 + 7 10^9+7 109+7 取模。
数据范围: 2 ≤ n ≤ 2 × 1 0 5 2 ≤ n ≤ 2\times10^5 2 ≤ n ≤ 2×105。
solution
这也是道神题啊 orz。
首先,欧拉函数有一个性质:
φ ( i j ) = φ ( i ) φ ( j ) gcd ( i , j ) φ ( gcd ( i , j ) ) \varphi(ij)=\varphi(i)\varphi(j)\frac{\gcd(i,j)}{\varphi(\gcd(i,j))} φ(ij)=φ(i)φ(j)φ(gcd(i,j))gcd(i,j)
这个根据 φ ( n ) = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p k ) \varphi(n)=n(1-\frac 1 {p_1})(1-\frac 1{p_2})\cdots(1-\frac 1{p_k}) φ(n)=n(1−p11)(1−p21)⋯(1−pk1) 即可推出。
先把 1 n ( n − 1 ) \frac 1{n(n-1)} n(n−1)1 抛开,考虑求:
a n s = ∑ i = 1 n ∑ j = 1 n φ ( a i ) φ ( a j ) gcd ( a i , a j ) φ ( gcd ( a i , a j ) ) × d i s ( i , j ) ans=\sum_{i=1}^n\sum_{j=1}^n\varphi(a_i)\varphi(a_j)\frac{\gcd(a_i,a_j)}{\varphi(\gcd(a_i,a_j))}\times \mathrm{dis}(i,j) ans=i=1∑nj=1∑nφ(ai)φ(aj)φ(gcd(ai,aj))gcd(ai,aj)×dis(i,j)
枚举 gcd \gcd gcd,得到:
a n s = ∑ k = 1 n k φ ( k ) ∑ i = 1 n ∑ j = 1 n [ gcd ( a i , a j ) = k ] φ ( a i ) φ ( a j ) × d i s ( i , j ) ans=\sum_{k=1}^n\frac{k}{\varphi(k)}\sum_{i=1}^n\sum_{j=1}^n[\gcd(a_i,a_j)=k]\varphi(a_i)\varphi(a_j)\times \mathrm{dis}(i,j) ans=k=1∑nφ(k)ki=1∑nj=1∑n[gcd(ai,aj)=k]φ(ai)φ(aj)×dis(i,j)
我们做一个小转化,设值 i i i 对应的点为 p i p_i pi,则:
a n s = ∑ k = 1 n k φ ( k ) ∑ i = 1 n ∑ j = 1 n [ gcd ( i , j ) = k ] φ ( i ) φ ( j ) × d i s ( p i , p j ) = ∑ k = 1 n k φ ( k ) ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ [ gcd ( i , j ) = 1 ] φ ( i k ) φ ( j k ) × d i s ( p i k , p j k ) \begin{aligned} ans&=\sum_{k=1}^n\frac{k}{\varphi(k)}\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=k]\varphi(i)\varphi(j)\times \mathrm{dis}(p_i,p_j)\\ &=\sum_{k=1}^n\frac{k}{\varphi(k)}\sum_{i=1}^{\lfloor\frac nk\rfloor}\sum_{j=1}^{\lfloor\frac nk\rfloor}[\gcd(i,j)=1]\varphi(ik)\varphi(jk)\times \mathrm{dis}(p_{ik},p_{jk}) \end{aligned} ans=k=1∑nφ(k)ki=1∑nj=1∑n[gcd(i,j)=k]φ(i)φ(j)×dis(pi,pj)=k=1∑nφ(k)ki=1∑⌊kn⌋j=1∑⌊kn⌋[gcd(i,j)=1]φ(ik)φ(jk)×dis(pik,pjk)
然后就可以莫反了:
a n s = ∑ k = 1 n k φ ( k ) ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ ∑ d ∣ gcd ( i , j ) μ ( d ) φ ( i k ) φ ( j k ) × d i s ( p i k , p j k ) = ∑ k = 1 n k φ ( k ) ∑ d = 1 ⌊ n k ⌋ μ ( d ) ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ n k d ⌋ φ ( i k d ) φ ( j k d ) × d i s ( p i k d , p j k d ) \begin{aligned} ans&=\sum_{k=1}^n\frac{k}{\varphi(k)}\sum_{i=1}^{\lfloor\frac nk\rfloor}\sum_{j=1}^{\lfloor\frac nk\rfloor}\sum_{d|\gcd(i,j)}\mu(d)\varphi(ik)\varphi(jk)\times \mathrm{dis}(p_{ik},p_{jk})\\ &=\sum_{k=1}^n\frac{k}{\varphi(k)}\sum_{d=1}^{{\lfloor\frac nk\rfloor}}\mu(d)\sum_{i=1}^{\lfloor\frac n{kd}\rfloor}\sum_{j=1}^{\lfloor\frac n{kd}\rfloor}\varphi(ikd)\varphi(jkd)\times \mathrm{dis}(p_{ikd},p_{jkd}) \end{aligned} ans=k=1∑nφ(k)ki=1∑⌊kn⌋j=1∑⌊kn⌋d∣gcd(i,j)∑μ(d)φ(ik)φ(jk)×dis(pik,pjk)=k=1∑nφ(k)kd=1∑⌊kn⌋μ(d)i=1∑⌊kdn⌋j=1∑⌊kdn⌋φ(ikd)φ(jkd)×dis(pikd,pjkd)
令 T = k d T=kd T=kd,我们枚举 T T T,得:
a n s = ∑ T = 1 n ∑ k ∣ T μ ( T k ) k φ ( k ) ∑ i = 1 ⌊ n T ⌋ ∑ j = 1 ⌊ n T ⌋ φ ( i T ) φ ( j T ) × d i s ( p i T , p j T ) ans=\sum_{T=1}^n\sum_{k|T}\frac{\mu(\frac Tk)k}{\varphi(k)}\sum_{i=1}^{\lfloor\frac n T\rfloor}\sum_{j=1}^{\lfloor\frac n T\rfloor}\varphi(iT)\varphi(jT)\times\mathrm{dis}(p_{iT},p_{jT}) ans=T=1∑nk∣T∑φ(k)μ(kT)ki=1∑⌊Tn⌋j=1∑⌊Tn⌋φ(iT)φ(jT)×dis(piT,pjT)
设 f ( n ) = ∑ k ∣ n μ ( n k ) k φ ( k ) f(n)=\sum_{k|n}\frac{\mu(\frac n k)k}{\varphi(k)} f(n)=∑k∣nφ(k)μ(kn)k,这个可以枚举倍数在 O ( n log n ) O(n\log n) O(nlogn) 的时间内算出来。
考虑怎么计算后面的那个式子,由于每次涉及的点只有 O ( ⌊ n T ⌋ ) O(\lfloor\frac n T\rfloor) O(⌊Tn⌋) 个,就想到可以在虚树上 d p dp dp。
具体就是,把虚树建出来之后,考虑一下每条边的贡献就可以了。
PS:注意最后别忘了除以 n ( n − 1 ) n(n-1) n(n−1)。
PPS:其实感觉这道题莫反挺套路的,关键是要想到那个转化和在虚树上 d p dp dp。
时间复杂度 O ( n log 2 n ) O(n\log^2n) O(nlog2n)。
code
#include<bits/stdc++.h>
#define N 200005
#define P 1000000007
using namespace std;
int n,tot;
int a[N],pos[N],dfn[N],dep[N],fa[N][21];
struct edge{
int t,first[N],v[N<<1],nxt[N<<1];
void add(int x,int y){
nxt[++t]=first[x],first[x]=t,v[t]=y;
}
}T,VT;
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
int power(int a,int b){
int ans=1;
for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a);
return ans;
}
int inv(int x) {return power(x,P-2);}
bool comp(const int &p,const int &q) {return dfn[p]<dfn[q];}
int sum,prime[N],mark[N],mu[N],phi[N],f[N];
void linear_sieves(){
phi[1]=mu[1]=1;
for(int i=2;i<N;++i){
if(!mark[i]) prime[++sum]=i,mu[i]=P-1,phi[i]=i-1;
for(int j=1;j<=sum&&i*prime[j]<N;++j){
mark[i*prime[j]]=1;
if(i%prime[j]) mu[i*prime[j]]=P-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);
else {mu[i*prime[j]]=0,phi[i*prime[j]]=phi[i]*prime[j];break;}
}
}
for(int i=1;i<N;++i){
int Inv=inv(phi[i]);
for(int j=1;i*j<N;++j)
f[i*j]=add(f[i*j],mul(mul(i,mu[j]),Inv));
}
}
void dfs(int x){
dfn[x]=++tot;
for(int i=1;i<=20;++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=T.first[x];i;i=T.nxt[i]){
int to=T.v[i];
if(to==fa[x][0]) continue;
fa[to][0]=x,dep[to]=dep[x]+1;
dfs(to);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;~i;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=20;~i;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
namespace Virtual_Tree{
int sum,res,cnt,top;
int p[N],S[N],stk[N];
void Insert(int x){
if(top==1) {stk[++top]=x;return;}
int lca=LCA(x,stk[top]);
if(lca==stk[top]) {stk[++top]=x;return;}
while(top>1&&dfn[lca]<=dfn[stk[top-1]])
VT.add(stk[top-1],stk[top]),top--;
if(lca!=stk[top]) VT.add(lca,stk[top]),stk[top]=lca;
stk[++top]=x;
}
int dis(int x,int y) {return dep[x]+dep[y]-2*dep[LCA(x,y)];}
void dp(int x){
for(int i=VT.first[x];i;i=VT.nxt[i]){
int to=VT.v[i],len=dis(x,to);
dp(to);
res=add(res,mul(len,mul(dec(sum,S[to]),S[to])));
S[x]=add(S[x],S[to]);
}
}
void Clear(int x){
for(int i=VT.first[x];i;i=VT.nxt[i]) Clear(VT.v[i]);
S[x]=VT.first[x]=0;
}
int calc(int x){
VT.t=cnt=sum=res=0;
for(int i=1;i*x<=n;++i) p[++cnt]=pos[i*x],S[p[cnt]]=phi[i*x],sum=add(sum,phi[i*x]);
sort(p+1,p+cnt+1,comp),stk[top=1]=1;
for(int i=1;i<=cnt;++i) if(p[i]!=1) Insert(p[i]);
while(--top) VT.add(stk[top],stk[top+1]);
dp(1),Clear(1);
res=mul(add(res,res),f[x]);
return res;
}
}
using namespace Virtual_Tree;
int main(){
scanf("%d",&n),linear_sieves();
for(int i=1;i<=n;++i) scanf("%d",&a[i]),pos[a[i]]=i;
for(int i=1,x,y;i<n;++i){
scanf("%d%d",&x,&y);
T.add(x,y),T.add(y,x);
}
dep[1]=1,dfs(1);
int ans=0;
for(int i=1;i<=n;++i) ans=add(ans,calc(i));
printf("%d\n",mul(ans,inv(mul(n,n-1))));
return 0;
}