CF809E Surprise me!
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{d\varphi(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\n",Mul(Mul(inv[n-1],inv[n]),ans));
return 0;
}