对于欧拉函数,有:
φ
(
a
∗
b
)
=
φ
(
a
)
∗
φ
(
b
)
∗
g
c
d
(
a
,
b
)
φ
(
g
c
d
(
a
,
b
)
)
\varphi (a*b)=\varphi(a)*\varphi(b)*\frac{gcd(a,b)}{\varphi(gcd(a,b))}
φ(a∗b)=φ(a)∗φ(b)∗φ(gcd(a,b))gcd(a,b)
证明:把
a
a
a和
b
b
b质因数分解即可。
那么首先由于点权为
1
1
1~
n
n
n的全排列,所以枚举点权,记录一下点权的所在点。
a
n
s
=
∑
φ
(
i
)
∗
φ
(
j
)
∗
g
c
d
(
i
,
j
)
φ
(
g
c
d
(
i
,
j
)
)
∗
d
i
s
(
p
[
i
]
,
p
[
j
]
)
ans=\sum\varphi(i)*\varphi(j)*\frac{gcd(i,j)}{\varphi(gcd(i,j))}*dis(p[i],p[j])
ans=∑φ(i)∗φ(j)∗φ(gcd(i,j))gcd(i,j)∗dis(p[i],p[j])
p
[
i
]
p[i]
p[i]:点权为
i
i
i的点对应原树上的点为
p
[
i
]
p[i]
p[i]。
这里
∑
\sum
∑没有标明上下界表示枚举树上的所有点对。
然后枚举
g
c
d
gcd
gcd(套路):
a
n
s
=
∑
d
=
1
n
d
φ
(
d
)
∑
[
g
c
d
(
i
,
j
)
=
=
d
]
φ
(
i
)
∗
φ
(
j
)
∗
d
i
s
(
p
[
i
]
,
p
[
j
]
)
ans=\sum_{d=1}^{n} {\frac{d}{\varphi(d)}} \sum {[gcd(i,j)==d]\varphi(i)*\varphi(j)*dis(p[i],p[j])}
ans=d=1∑nφ(d)d∑[gcd(i,j)==d]φ(i)∗φ(j)∗dis(p[i],p[j])
后面是一个可以莫比乌斯反演的形式。我们令:
g
(
d
)
=
∑
[
g
c
d
(
i
,
j
)
=
=
d
]
φ
(
i
)
∗
φ
(
j
)
∗
d
i
s
(
p
[
i
]
,
p
[
j
]
)
g(d)= \sum {[gcd(i,j)==d]\varphi(i)*\varphi(j)*dis(p[i],p[j])}
g(d)=∑[gcd(i,j)==d]φ(i)∗φ(j)∗dis(p[i],p[j])
f
(
d
)
=
∑
[
d
∣
g
c
d
(
i
,
j
)
]
φ
(
i
)
∗
φ
(
j
)
∗
d
i
s
(
p
[
i
]
,
p
[
j
]
)
f(d)= \sum {[d|gcd(i,j)]\varphi(i)*\varphi(j)*dis(p[i],p[j])}
f(d)=∑[d∣gcd(i,j)]φ(i)∗φ(j)∗dis(p[i],p[j])
于是有:
f
(
d
)
=
∑
d
∣
k
g
(
k
)
f(d)=\sum_{d|k}g(k)
f(d)=d∣k∑g(k)
由莫比乌斯反演:
f
(
d
)
=
∑
d
∣
k
g
(
k
)
⟺
g
(
d
)
=
∑
d
∣
k
μ
(
k
d
)
f
(
k
)
f(d)=\sum_{d|k}g(k) \Longleftrightarrow g(d)=\sum_{d|k} {\mu(\frac{k}{d})f(k)}
f(d)=d∣k∑g(k)⟺g(d)=d∣k∑μ(dk)f(k)
回过头来看:
a
n
s
=
∑
d
=
1
n
d
φ
(
d
)
g
(
d
)
ans=\sum_{d=1}^{n} {\frac{d}{\varphi(d)}} g(d)
ans=d=1∑nφ(d)dg(d)
a
n
s
=
∑
d
=
1
n
d
φ
(
d
)
∑
d
∣
k
μ
(
k
d
)
f
(
k
)
ans=\sum_{d=1}^{n} {\frac{d}{\varphi(d)}} \sum_{d|k} {\mu(\frac{k}{d})f(k)}
ans=d=1∑nφ(d)dd∣k∑μ(dk)f(k)
如果我们可以预处理出所有的
f
f
f,我们就可以在
O
(
n
+
n
l
o
g
n
)
O(n+nlogn)
O(n+nlogn)的时间内枚举
d
d
d以及
d
d
d的倍数然后得到答案了。
于是考虑怎么预处理 f f f
f ( d ) = ∑ [ d ∣ g c d ( i , j ) ] φ ( i ) ∗ φ ( j ) ∗ d i s ( p [ i ] , p [ j ] ) f(d)= \sum {[d|gcd(i,j)]\varphi(i)*\varphi(j)*dis(p[i],p[j])} f(d)=∑[d∣gcd(i,j)]φ(i)∗φ(j)∗dis(p[i],p[j])
f ( d ) = ∑ d ∣ i ∑ d ∣ j φ ( i ) ∗ φ ( j ) ∗ d i s ( p [ i ] , p [ j ] ) f(d)= \sum_{d|i} \sum_{d|j}{\varphi(i)*\varphi(j)*dis(p[i],p[j])} f(d)=d∣i∑d∣j∑φ(i)∗φ(j)∗dis(p[i],p[j])
f ( d ) = ∑ d ∣ i ∑ d ∣ j φ ( i ) ∗ φ ( j ) ∗ ( d e p [ p [ i ] ] + d e p [ p [ j ] ] − 2 ∗ d e p [ l c a ] ) f(d)= \sum_{d|i} \sum_{d|j}{\varphi(i)*\varphi(j)*(dep[p[i]]+dep[p[j]]-2*dep[lca])} f(d)=d∣i∑d∣j∑φ(i)∗φ(j)∗(dep[p[i]]+dep[p[j]]−2∗dep[lca])
f ( d ) = ∑ d ∣ i ∑ d ∣ j φ ( i ) ∗ φ ( j ) ∗ d e p [ p [ i ] ] + ∑ d ∣ i ∑ d ∣ j φ ( i ) ∗ φ ( j ) ∗ d e p [ p [ j ] ] − ∑ d ∣ i ∑ d ∣ j φ ( i ) ∗ φ ( j ) ∗ d e p [ l c a ] ∗ 2 f(d)= \sum_{d|i} \sum_{d|j}{\varphi(i)*\varphi(j)*dep[p[i]]}+ \sum_{d|i} \sum_{d|j}{\varphi(i)*\varphi(j)*dep[p[j]]}- \sum_{d|i} \sum_{d|j}{\varphi(i)*\varphi(j)*dep[lca]*2} f(d)=d∣i∑d∣j∑φ(i)∗φ(j)∗dep[p[i]]+d∣i∑d∣j∑φ(i)∗φ(j)∗dep[p[j]]−d∣i∑d∣j∑φ(i)∗φ(j)∗dep[lca]∗2
我们枚举
d
d
d,提取出点权为
d
d
d的倍数的点。发现前面两坨是一样的,可以直接算,而后面一坨可以建一棵虚树出来
d
p
dp
dp。
每次虚树的点是
n
d
\frac{n}{d}
dn个,求一次是
O
(
n
d
)
O(\frac{n}{d})
O(dn)的。于是可以在
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的时间里面把
f
f
f求出来。
然后把
f
f
f套进刚才
a
n
s
ans
ans的那个式子里就行了。
最后要记得乘上
1
n
∗
(
n
−
1
)
\frac{1}{n*(n-1)}
n∗(n−1)1
①建虚树的时候是强制
1
1
1号点为根节点!
②虚树上不是所有点都是关键点,因为有一些辅助的
l
c
a
lca
lca节点,所以要给关键点打上标记。
#include<bits/stdc++.h>
#define re register
#define cs const
cs int N=2e5+10,Log=18;
int mark[N],P[N],mu[N],phi[N],cnt=0;
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch;T x;
while(!isdigit(ch=gc()));x=ch^48;
while(isdigit(ch=gc())) x=((x+(x<<2))<<1)+(ch^48);
return x;
}
inline int gi(){return get<int>();}
}
using namespace IO;
int dep[N],dfn[N],t[N<<1],tot=0;
int dp[N<<1][Log+1];
namespace GRAPH{
int Head[N],Next[N<<1],V[N<<1],cnt=0;
inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
inline void dfs(int u,int fa){
t[dfn[u]=++tot]=u,dep[u]=dep[fa]+1;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(v!=fa) dfs(v,u),t[++tot]=u;
}
inline void RMQ(){
for(int re j=0;(1<<j)<tot;++j)
for(int re i=0;i+(1<<j)<=tot;++i)
if(j==0) dp[i][j]=i;
else{
if(dep[t[dp[i][j-1]]]<dep[t[dp[i+(1<<(j-1))][j-1]]])
dp[i][j]=dp[i][j-1];
else dp[i][j]=dp[i+(1<<(j-1))][j-1];
}
}
inline int query(int p1,int p2){
int k=log2(p2-p1+1);
if(dep[t[dp[p1][k]]]<dep[t[dp[p2-(1<<k)+1][k]]])
return t[dp[p1][k]];
else return t[dp[p2-(1<<k)+1][k]];
}
inline int lca(int u,int v){
if(dfn[u]>dfn[v]) std::swap(u,v);
return query(dfn[u],dfn[v]);
}
}
using GRAPH::lca;
namespace CALC{
cs int mod=1e9+7;
inline int plu(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int sqr(int x){return 1ll*x*x%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=sqr(a))if(b&1)ret=mul(ret,a);return ret;}
inline int inv(int x){return quickpow(x,mod-2);}
inline void linear_sieves(){
mark[1]=phi[1]=mu[1]=1;
for(int re i=2;i<N;++i){
if(!mark[i]) P[++cnt]=i,mu[i]=mod-1,phi[i]=i-1;
for(int re j=1;j<=cnt&&i*P[j]<N;++j){
mark[i*P[j]]=1;
if(i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1),mu[i*P[j]]=dec(mod,mu[i]);
else{phi[i*P[j]]=phi[i]*P[j],mu[i*P[j]]=0;break;}
}
}
}
}
using CALC::mul;
using CALC::sqr;
using CALC::inv;
using CALC::dec;
using CALC::plu;
int n,pos[N],val[N],F[N],ans=0;
namespace V_TREE{
cs int Log=18;
int Head[N],Next[N<<1],V[N<<1],cnt=0;
int sum[N],tag[N],st[N],q[N],top=0,qn=0;
inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline void init(){cnt=top=qn=0;}
inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
inline void insert(int u){
if(top==1) return void(st[++top]=u);
int g=lca(u,st[top]);
if(g==st[top]) return void(st[++top]=u);
while(top>1&&dfn[g]<=dfn[st[top-1]])
add(st[top-1],st[top]),--top;
if(g!=st[top]) add(g,st[top]),st[top]=g;
st[++top]=u;
}
inline int dfs(int u,int ret=0,int now=0){
sum[u]=tag[u]?phi[val[u]]:0;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]){
ret=plu(ret,dfs(v)),now=dec(now,sqr(sum[v]));
sum[u]=plu(sum[u],sum[v]);
}now=plu(now,sqr(sum[u])),tag[u]=Head[u]=0;
return plu(ret,mul(dep[u]<<1,now));
}
inline int get_f(int k,int sum_phi=0,int sum_mul=0){
init();
for(int re i=k;i<=n;i+=k)
tag[q[++qn]=pos[i]]=1,sum_phi=plu(sum_phi,phi[i]),
sum_mul=plu(sum_mul,mul(phi[i],dep[pos[i]]));
std::sort(q+1,q+qn+1,cmp),st[top=1]=1;
for(int re i=1;i<=qn;++i) if(q[i]!=1) insert(q[i]);
while(--top) add(st[top],st[top+1]);
return dec(mul(2,mul(sum_mul,sum_phi)),dfs(1));
}
}
int main(){
#ifdef wcr
freopen("surprise.in","r",stdin);
#endif
CALC::linear_sieves();
n=gi();
for(int re i=1;i<=n;++i) pos[val[i]=gi()]=i;
for(int i=1;i<n;++i){
int x=gi(),y=gi();
GRAPH::add(x,y),GRAPH::add(y,x);
}GRAPH::dfs(1,0),GRAPH::RMQ();
for(int re i=1;i<=n;++i) F[i]=V_TREE::get_f(i);
for(int re d=1,sum=0;d<=n;++d,sum=0){
for(int re k=d,i=1;k<=n;k+=d,++i)
sum=plu(sum,mul(mu[i],F[k]));
ans=plu(ans,mul(sum,mul(d,inv(phi[d]))));
}printf("%d\n",mul(inv(mul(n,n-1)),ans));
}
本文深入探讨了欧拉函数的性质及其与莫比乌斯反演的关系,通过点权为1到n的全排列,介绍了如何利用欧拉函数和莫比乌斯反演解决特定的数学问题,包括复杂度分析和算法实现。
12万+

被折叠的 条评论
为什么被折叠?



