CF809E Surprise me!
题面:Luogu
解析
题意即求:
[frac{1}{n(n-1)}sum_{i=1}^{n}sum_{j=1}^{n}varphi(a_{i}a_{j})dist(i,j)
]
其中,(a_{i})为(n)的一个排列。
首先有:(varphi(ij)=frac{dvarphi(i)varphi(j)}{varphi(d)}),其中(d=gcd(i,j)),证明带入公式即可。
那么有:
[sum_{i=1}^{n}sum_{j=1}^{n}varphi(a_{i}a_{j})dist(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})dist(i,j)
]
考虑莫比乌斯反演,设:
[g(d)=sum_{i=1}^{n}sum_{j=1}^{n}[gcd(a_{i},a_{j})=d]varphi(a_{i})varphi(a_{j})dist(i,j)
]
[f(d)=sum_{i=1}^{n}sum_{j=1}^{n}[d|gcd(a_{i},a_{j})]varphi(a_{i})varphi(a_{j})dist(i,j)
]
那么有:
[=sum_{d=1}^{n}frac{d}{varphi(d)}sum_{d|k}mu(frac{k}{d})f(k)
]
求出(f(k))后枚举倍数贡献即可(O(nlogn))统计答案,考虑如何计算(f(k))。
观察到只有(a_{i})是(k)的倍数才有贡献,那我们把(k)的倍数的点提出来建虚树。
现在就是求:
[sum_{i=1}^{t}sum_{j=1}^{t}varphi(a_{i})varphi(a_{j})dist(i,j)
]
[=sum_{i=1}^{t}varphi(a_{i})dep[i]sum_{j=1}^{t}varphi(a_{j})+sum_{i=1}^{t}varphi(a_{i})sum_{j=1}^{t}varphi(a_{j})dep[j]-2*sum_{i=1}^{t}sum_{j=1}^{t}varphi(a_{i})varphi(a_{j})d[lca]
]
前面两部分可以(O(n))统计,后面一部分可以枚举(lca),组合一下子树,也可以(O(n))统计。
那么总复杂度即为(O(nlogn)),解决了这个问题。
代码
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
inline int In(){
char c=getchar();
int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()){
if(c=='-'){
ft=-1;
}
}
for(;c>='0'&&c<='9';c=getchar()){
x=x*10+c-'0';
}
return x*ft;
}
const int P=1e9+7,N=2e5+5;
inline void Add(int& x,int y){
x+=y;
if(x>=P){
x-=P;
}
}
inline int Mul(int x,int y){
return 1ll*x*y%P;
}
int n,a[N],pos[N],inv[N];
int h[N],e_tot=0;
struct Edge{
int to,nex;
Edge(){}
Edge(int to,int nex):to(to),nex(nex){}
}e[N<<1];
inline void add(int u,int v){
e[++e_tot]=Edge(v,h[u]);
h[u]=e_tot;
}
int d[N],fa[N],sz[N],son[N];
void dfs1(int u,int pre){
d[u]=d[pre]+1;
fa[u]=pre;
sz[u]=1;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to;
if(v==fa[u]){
continue;
}
dfs1(v,u);
sz[u]+=sz[v];
if(!son[u]||sz[v]>sz[son[u]]){
son[u]=v;
}
}
}
int top[N],dfn[N],low[N],dfc=0;
void dfs2(int u,int pre){
top[u]=pre;
dfn[u]=++dfc;
if(son[u]){
dfs2(son[u],pre);
}
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to;
if(v==fa[u]||v==son[u]){
continue;
}
dfs2(v,v);
}
low[u]=dfc;
}
inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]){
swap(x,y);
}
x=fa[top[x]];
}
return d[x]<d[y]?x:y;
}
int p[N],pc,mu[N],phi[N];
bool vis[N];
void Sieve(int n){
mu[1]=phi[1]=1;
for(int i=2;i<=n;++i){
if(!vis[i]){
p[++pc]=i;
mu[i]=-1;
phi[i]=i-1;
}
for(int j=1;j<=pc;++j){
if(1ll*i*p[j]>n){
break;
}
vis[i*p[j]]=1;
if(i%p[j]){
mu[i*p[j]]=-mu[i];
phi[i*p[j]]=phi[i]*(p[j]-1);
}
else{
mu[i*p[j]]=0;
phi[i*p[j]]=phi[i]*p[j];
break;
}
}
}
}
int t[N<<1],tc,stk[N];
vector<int> E[N];
inline bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
inline void add_edge(int u,int v){
E[u].push_back(v);
}
int ans,sum1,sum2,sum3,sum[N],f[N],g[N];
bool fg[N];
void dfs(int u){
if(fg[u]){
Add(sum1,phi[a[u]]);
Add(sum2,Mul(phi[a[u]],d[u]));
sum[u]=phi[a[u]];
Add(sum3,Mul(d[u],Mul(phi[a[u]],phi[a[u]])));
}
for(int i=0,v;i<E[u].size();++i){
v=E[u][i];
dfs(v);
Add(sum3,Mul(d[u],Mul(2,Mul(sum[u],sum[v]))));
Add(sum[u],sum[v]);
}
}
void del(int u){
sum[u]=fg[u]=0;
for(int i=0,v;i<E[u].size();++i){
v=E[u][i];
del(v);
}
E[u].clear();
}
int main(){
n=In();
for(int i=1;i<=n;++i){
a[i]=In();
pos[a[i]]=i;
}
for(int i=1,u,v;i<n;++i){
u=In();
v=In();
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,1);
Sieve(n);
inv[0]=inv[1]=1;
for(int i=2;i<=n;++i){
inv[i]=Mul(P-P/i,inv[P%i]);
}
for(int d=1;d<=n;++d){
tc=0;
for(int i=d;i<=n;i+=d){
t[++tc]=pos[i];
fg[pos[i]]=1;
}
sort(t+1,t+1+tc,cmp);
for(int i=tc;i>1;--i){
t[++tc]=LCA(t[i-1],t[i]);
}
sort(t+1,t+1+tc,cmp);
tc=unique(t+1,t+1+tc)-t-1;
stk[1]=t[1];
for(int i=2,stp=1;i<=tc;++i){
while(stp&&low[stk[stp]]<dfn[t[i]]){
--stp;
}
add_edge(stk[stp],t[i]);
stk[++stp]=t[i];
}
sum1=sum2=sum3=0;
dfs(t[1]);
Add(f[d],Mul(2,Mul(sum1,sum2)));
Add(f[d],P-Mul(2,sum3));
del(t[1]);
}
for(int d=1;d<=n;++d){
for(int i=d;i<=n;i+=d){
Add(g[d],Mul(f[i],(mu[i/d]+P)%P));
}
}
for(int d=1;d<=n;++d){
Add(ans,Mul(Mul(d,inv[phi[d]]),g[d]));
}
printf("%d
",Mul(Mul(inv[n-1],inv[n]),ans));
return 0;
}