Codeforces
有一棵树,第 i i i 个点的点权为 a i a_i ai,保证 a i a_i ai 是一个排列,求
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_i*a_j)*dis(i,j) n(n−1)1i=1∑nj=1∑nφ(ai∗aj)∗dis(i,j)
常数可以先丢掉,由
(1) φ ( a b ) = φ ( a ) φ ( b ) gcd ( a , b ) φ ( gcd ( a , b ) ) \varphi(ab)=\frac {\varphi(a)\varphi(b)\gcd(a,b)} {\varphi(\gcd(a,b))}\tag 1 φ(ab)=φ(gcd(a,b))φ(a)φ(b)gcd(a,b)(1)
可以把式子改成枚举 gcd \gcd gcd 的形式
∑ d = 1 n d φ ( d ) ∑ i = 1 n ∑ j = 1 n [ gcd ( a i , a j ) = d ] φ ( a i ) φ ( a j ) d i s ( i , j ) \sum_{d=1}^n\frac {d} {\varphi(d)}\sum_{i=1}^n\sum_{j=1}^n[\gcd(a_i,a_j)=d]\varphi(a_i)\varphi(a_j)dis(i,j) d=1∑nφ(d)di=1∑nj=1∑n[gcd(ai,aj)=d]φ(ai)φ(aj)dis(i,j)
f ( d ) = d φ ( d ) ∑ i = 1 n ∑ j = 1 m [ ( a i , a j ) = 1 ] φ ( a i ) φ ( a j ) ∗ d i s ( i , j ) f(d)=\frac {d} {\varphi(d)}\sum_{i=1}^n\sum_{j=1}^m[(a_i,a_j)=1]\varphi(a_i)\varphi(a_j)*dis(i,j) f(d)=φ(d)di=1∑nj=1∑m[(ai,aj)=1]φ(ai)φ(aj)∗dis(i,j)
F ( d ) = d φ ( d ) ∑ i = 1 n ∑ j = 1 n [ d ∣ ( a i , a j ) ] φ ( a i ) φ ( a j ) ∗ d i s ( i , j ) F(d)=\frac {d} {\varphi(d)}\sum_{i=1}^n\sum_{j=1}^n[d|(a_i,a_j)]\varphi(a_i)\varphi(a_j)*dis(i,j) F(d)=φ(d)di=1∑nj=1∑n[d∣(ai,aj)]φ(ai)φ(aj)∗dis(i,j)
f ( d ) = ∑ d ∣ i μ ( i d ) F ( i ) f(d)=\sum_{d|i}\mu(\frac i d)F(i) f(d)=d∣i∑μ(di)F(i)
暴力枚举 d d d,注意到总点数为 n ln n n\ln n nlnn,那么可以通过在虚树上dfs的求出 F ( d ) F(d) F(d)。
时间复杂度 O ( n ln n log n ) O(n\ln n\log n) O(nlnnlogn)。写起来还挺爽的。。
#include
#include
using namespace std;
typedef long long ll;
const int maxn=200010,mod=1e9+7;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int n,ans,a[maxn],id[maxn],f[maxn],g[maxn];
namespace Math{
int tot,pri[maxn],phi[maxn],mu[maxn];
int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x<y?x-y+mod:x-y;}
int power(int x,int y)
{
int res=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1)
res=(ll)res*x%mod;
return res;
}
void init()
{
phi[1]=mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!phi[i]) phi[i]=i-1,mu[i]=mod-1,pri[++tot]=i;
for(int j=1;j<=tot&&i*pri[j]<=n;j++)
{
if(i%pri[j]==0)
{
phi[i*pri[j]]=phi[i]*pri[j];
mu[i*pri[j]]=0;
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
mu[i*pri[j]]=dec(0,mu[i]);
}
}
}
}
using Math::phi;
using Math::mu;
using Math::pls;
using Math::dec;
using Math::power;
namespace Tree{
struct data{int v,nxt;}edge[maxn<<1];
int p,dfc,head[maxn],dfn[maxn],f[maxn],dep[maxn],sz[maxn],hs[maxn],top[maxn];
int cmp(const int &x,const int &y){return dfn[x]<dfn[y];}
void insert(int u,int v)
{
edge[++p]=(data){v,head[u]};head[u]=p;
edge[++p]=(data){u,head[v]};head[v]=p;
}
void dfs1(int x)
{
sz[x]=1;dep[x]=dep[f[x]]+1;dfn[x]=++dfc;
for(int i=head[x];i;i=edge[i].nxt)
if(edge[i].v^f[x])
{
f[edge[i].v]=x;
dfs1(edge[i].v);
sz[x]+=sz[edge[i].v];
if(sz[edge[i].v]>sz[hs[x]]) hs[x]=edge[i].v;
}
}
void dfs2(int x,int s)
{
top[x]=s;
if(hs[x]) dfs2(hs[x],s);
for(int i=head[x];i;i=edge[i].nxt)
if(edge[i].v^f[x]&&edge[i].v^hs[x])
dfs2(edge[i].v,edge[i].v);
}
int getlca(int x,int y)
{
int fx=top[x],fy=top[y];
while(fx^fy)
{
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
x=f[fx];fx=top[x];
}
return dep[x]<dep[y]?x:y;
}
}
using Tree::dep;
using Tree::insert;
using Tree::getlca;
using Tree::cmp;
namespace Virtual_Tree{
struct data{int v,nxt;}edge[maxn<<1];
int p,m,top,rt,sum,res,head[maxn],q[maxn],stk[maxn],tag[maxn];
void insert(int u,int v)
{
edge[++p]=(data){v,head[u]};head[u]=p;
edge[++p]=(data){u,head[v]};head[v]=p;
}
void build()
{
int t=0;top=0;
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;i++)
{
while(top)
{
t=getlca(q[i],stk[top]);
if(top>1&&dep[t]<dep[stk[top-1]])
{insert(stk[top-1],stk[top]);--top;}
else if(dep[t]<dep[stk[top]])
{insert(t,stk[top]);--top;break;}
else break;
}
if(stk[top]^t){stk[++top]=t;if(!rt||dep[t]<dep[rt]) rt=t;}
stk[++top]=q[i];tag[q[i]]=1;
if(!rt||dep[q[i]]<dep[rt]) rt=t;
}
for(;top>1;--top) insert(stk[top-1],stk[top]);
}
int dfs(int x,int pre)
{
int sp=tag[x]?phi[a[x]]:0,sum=0,tmp;
for(int i=head[x];i;i=edge[i].nxt)
if(edge[i].v^pre)
{
tmp=dfs(edge[i].v,x);
sum=(sum+(ll)sp*tmp)%mod;
sp=pls(sp,tmp);
}
head[x]=0;
res=dec(res,4ll*dep[x]*sum%mod);
return sp;
}
int work()
{
res=sum=rt=0;
build();
for(int i=1;i<=m;i++) sum=pls(sum,phi[a[q[i]]]);
for(int i=1;i<=m;i++)
res=(res+(ll)phi[a[q[i]]]*dep[q[i]]%mod*dec(sum,phi[a[q[i]]]))%mod;
sum=0;
for(int i=1;i<=m;i++) sum=(sum+(ll)phi[a[q[i]]]*dep[q[i]])%mod;
for(int i=1;i<=m;i++)
res=(res+(ll)phi[a[q[i]]]*dec(sum,(ll)phi[a[q[i]]]*dep[q[i]]%mod))%mod;
dfs(rt,rt);
p=0;
for(int i=1;i<=m;i++) tag[q[i]]=0;
return res;
}
}
using Virtual_Tree::q;
using Virtual_Tree::m;
using Virtual_Tree::work;
void input()
{
int u,v;read(n);
for(int i=1;i<=n;i++){read(a[i]);id[a[i]]=i;}
for(int i=1;i<n;i++){read(u);read(v);insert(u,v);}
Math::init();
Tree::dfs1(1);
Tree::dfs2(1,1);
}
int main()
{
input();
for(int i=1;i<=n;i++)
{
m=0;
for(int j=i;j<=n;j+=i) q[++m]=id[j];
g[i]=work();
}
for(int i=1;i<=n;i++)
{
for(int j=i,r=1;j<=n;j+=i,++r)
f[i]=(f[i]+(ll)mu[r]*g[j])%mod;
ans=(ans+(ll)f[i]*i%mod*power(phi[i],mod-2))%mod;
}
ans=(ll)ans*power((ll)n*(n-1)%mod,mod-2)%mod;
printf("%d\n",ans);
return 0;
}