题目

这是一道神仙题

看到这样一个鬼畜的柿子

\[\sum_{i=1}^n\sum_{j=1}^n\varphi(a_i\times a_j)\times dis(i,j)
\]

又是树上距离又是\(\varphi\)的看起来根本就不知道怎么搞啊

首先需要知道一个这样的性质

\[\varphi(a\times b)=\frac{\varphi(a)\times \varphi(b)\times d}{\varphi(d)},d=(a,b)
\]

这个性质非常显然

设\(a=p^{k_1},b=p^{k_2},k_1<k_2\)

于是\(d=p^{k_1}\)

\[\varphi(a\times b)=\varphi(p^{k_1+k_2})=p^{k_1+k_2-1}(p-1)
\]

\[\frac{\varphi(a)\times \varphi(b)\times d}{\varphi(d)}=\frac{p^{k_1-1}p^{k_2-1}(p-1)^2p^{k_1}}{p^{k_1-1}(p-1)}=p^{k_1+k_2-1}(p-1)
\]

这个东西显然是积性的,扩展到多个质因子也是成立的

于是写成

\[\sum_{i=1}^n\sum_{j=1}^n\frac{\varphi(a_i)\times \varphi(a_j)\times (a_i,a_j)}{\varphi((a_i,a_j))}\times dis(i,j)
\]

套路枚举\(gcd\)

\[\sum_{d=1}^n\frac{d}{\varphi(d)}\sum_{i=1}^n\sum_{j=1}^n[(a_i,a_j)=d]\varphi(a_i)\times \varphi(a_j)\times dis(i,j)
\]

考虑设后面那个东西叫

\[f(d)=\sum_{i=1}^n\sum_{j=1}^n[(a_i,a_j)=d]\varphi(a_i)\times \varphi(a_j)\times dis(i,j)
\]

显然我们还需要一个函数叫

\[F(d)=\sum_{i=1}^n\sum_{j=1}^n[d|(a_i,a_j)]\varphi(a_i)\times \varphi(a_j)\times dis(i,j)
\]

我们可以直接反演了

\[F(d)=\sum_{d|n}f(n)
\]

\[f(d)=\sum_{d|n}\mu(\frac{n}{d})F(n)
\]

现在的问题就是求出\(F\),我们就可以做了

显然树上的点都有一个约数\(d\)的时候,任意两点的的\(gcd\)就会是\(d\)的倍数

我们如果把\(d|a_i\)的\(i\)拿出来,建出一棵虚树,搞一个树形\(dp\)

求一下

\[dp_i=\sum_{j=1}^ndis(i,j)\varphi(a_j)
\]

就好了,这就是一个小学生\(dp\)求树上带权重心了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
const int maxn=2e5+5;
const LL mod=1e9+7;
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,w;}e[maxn<<1];
int dfn[maxn],son[maxn],deep[maxn],a[maxn],b[maxn],P[maxn];
int Top[maxn],st[maxn],num,n,__,top,head[maxn],fa[maxn];
int f[maxn],p[maxn>>1],mu[maxn],phi[maxn];
LL dp[maxn],sum[maxn],S,inv[maxn],F[maxn];
inline int cmp(int a,int b) {return dfn[a]<dfn[b];}
inline LL ksm(LL a,int b) {
LL S=1;
while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}
return S;
}
inline void add(int x,int y,int w) {
e[++num].v=y;e[num].nxt=head[x];
head[x]=num;e[num].w=w;
}
void dfs1(int x) {
int maxx=-1;sum[x]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(deep[e[i].v]) continue;
deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
dfs1(e[i].v);sum[x]+=sum[e[i].v];
if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
}
}
void dfs2(int x,int topf) {
Top[x]=topf;dfn[x]=++__;
if(!son[x]) return;
dfs2(son[x],topf);
for(re int i=head[x];i;i=e[i].nxt)
if(!Top[e[i].v]) dfs2(e[i].v,e[i].v);
}
inline int LCA(int x,int y) {
while(Top[x]!=Top[y]) {
if(deep[Top[x]]<deep[Top[y]]) std::swap(x,y);
x=fa[Top[x]];
}
if(deep[x]<deep[y]) return x;return y;
}
inline void ins(int x) {
if(top<=1) {st[++top]=x;return;}
int lca=LCA(st[top],x);
if(lca==st[top]) {st[++top]=x;return;}
while(top>1&&dfn[st[top-1]]>=dfn[lca])
add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--;
if(lca!=st[top]) {add(lca,st[top],deep[st[top]]-deep[lca]);st[top]=lca;}
st[++top]=x;
}
void dfs(int x) {
sum[x]=f[x]*phi[a[x]];
for(re int i=head[x];i;i=e[i].nxt) {
dfs(e[i].v);
sum[x]+=sum[e[i].v];
dp[x]+=(dp[e[i].v]+sum[e[i].v]*(LL)e[i].w%mod)%mod;
dp[x]%=mod;
}
}
void reDfs(int x) {
for(re int i=head[x];i;i=e[i].nxt) {
LL now=dp[x]-(dp[e[i].v]+sum[e[i].v]*(LL)e[i].w%mod)%mod;
now=(now+mod)%mod;
dp[e[i].v]=(dp[e[i].v]+now+((S-sum[e[i].v])*(LL)e[i].w)%mod)%mod;
reDfs(e[i].v);
}
}
void clear(int x) {
f[x]=dp[x]=sum[x]=0;
for(re int i=head[x];i;i=e[i].nxt) clear(e[i].v);
head[x]=0;
}
int main() {
n=read();
for(re int i=1;i<=n;i++) a[i]=read();
for(re int x,y,i=1;i<n;i++)
x=read(),y=read(),add(x,y,0),add(y,x,0);
deep[1]=1,dfs1(1),dfs2(1,1);
for(re int i=1;i<=n;i++) b[a[i]]=i;
f[1]=mu[1]=phi[1]=1;
for(re int i=2;i<=n;i++) {
if(!f[i]) p[++p[0]]=i,mu[i]=-1,phi[i]=i-1;
for(re int j=1;j<=p[0]&&p[j]*i<=n;j++) {
f[p[j]*i]=1;
if(i%p[j]==0) {
phi[p[j]*i]=p[j]*phi[i];
break;
}
mu[p[j]*i]=-1*mu[i];
phi[p[j]*i]=(p[j]-1)*phi[i];
}
}
inv[1]=1;
for(re int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
memset(head,0,sizeof(head));
memset(f,0,sizeof(f));
memset(sum,0,sizeof(sum));
for(re int k=1;k<=n;k++) {
int tot=0;
num=0,top=0;
for(re int j=k;j<=n;j+=k)
P[++tot]=b[j],f[P[tot]]=1;
std::sort(P+1,P+tot+1,cmp);
int rt=P[1];
for(re int i=2;i<=tot;i++) rt=LCA(rt,P[i]);
if(!f[rt]) st[++top]=rt;
for(re int i=1;i<=tot;i++) ins(P[i]);
while(top) add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--;
dfs(rt);S=sum[rt];reDfs(rt);
for(re int i=1;i<=tot;i++)
F[k]=(F[k]+(LL)phi[a[P[i]]]*dp[P[i]]%mod)%mod;
clear(rt);
}
LL ans=0;
for(re int i=1;i<=n;i++) {
LL now=0;
for(re int j=i;j<=n;j+=i)
now=(now+F[j]*mu[j/i]%mod)%mod,now=(now+mod)%mod;
ans=(ans+now*(LL)i%mod*inv[phi[i]]%mod)%mod;
}
LL now=(LL)n*(LL)(n-1);
now%=mod;
printf("%lld\n",ksm(now,mod-2)*ans%mod);
return 0;
}

【CF809E】Surprise me!的更多相关文章

  1. 【CF809E】Surprise me!(动态规划,虚树,莫比乌斯反演)

    [CF809E]Surprise me!(动态规划,虚树,莫比乌斯反演) 题面 洛谷 CodeForces 翻译: 给定一棵\(n\)个节点的树,每个点有一个权值\(a[i]\),保证\(a[i]\) ...

  2. 【CF809E】Surprise me! 树形DP 虚树 数学

    题目大意 给你一棵\(n\)个点的树,每个点有权值\(a_i\),\(a\)为一个排列,求 \[ \frac{1}{n(n-1)}\sum_{i=1}^n\sum_{j=1}^n \varphi(a_ ...

  3. 【转】python f-string

    [转]python f-string   文章目录 1. 主要内容 1.1. 旧时代的格式化字符串 1.1.1. Option #1: %-formatting 1.1.2. 怎样使用 %-forma ...

  4. 【Gabor】基于多尺度多方向Gabor融合+分块直方图的表情识别

    Topic:表情识别Env: win10 + Pycharm2018 + Python3.6.8Date:   2019/6/23~25 by hw_Chen2018                  ...

  5. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  6. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  7. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  8. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  9. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

随机推荐

  1. [javaSE] 网络编程(TCP,UDP,Socket特点)

    UDP特点: 面向无连接,把数据打包发过去,收不收得到我不管 数据大小有限制,一次不能超过64k,可以分成多个包 这是个不可靠的协议 速度很快 视频直播,凌波客户端,feiQ都是UDP协议 TCP特点 ...

  2. 腾讯云CentOS安装JDK1.8

    购买了腾讯云CentOS7系统,尝试搭建一个博客平台,首先要安装JDK. 一开始尝试用本地FTP上传JDK包到服务器,速度太慢,只有10K左右,放弃. 然后决定在服务器直接下载JDK进行安装. 执行 ...

  3. shell与expect结合使用

    在linux操作系统下,使用脚本自动化,一般由两种方案,方案一:telnet+ftp,方案二:ssh+scp+expect. 以下主要使用ssh+scp+expect为例进行说明使用方式. 第一步:安 ...

  4. Linux CPU使用率的计算

         CPU 使用率衡量的是程序运行占用的CPU 百分比.Linux 的CPU 使用率信息可以通过/proc/stat 文件计算得到. proc 文件系统       /proc 文件系统是一个伪 ...

  5. BootStrap-select 插件的使用

    这是一款下拉框多选的插件,非常的抢到,什么样式都是有的:首先去参看一下官网的信息,详细介绍是怎么使用的: 相关官网网址:  https://silviomoreto.github.io/bootstr ...

  6. 获取本地IP地址的vc代码

    作者:朱金灿 来源:http://blog.csdn.net/clever101 获取本地IP地址有两种做法.一种是使用gethostname函数,代码如下: bool CSocketComm::Ge ...

  7. 漂亮的ActionBar效果

    Newsstand—这个应用引进了新的方式,使得ActionBar达到了新的水平.如果你打开这个应用的发布页,你会注意到不带图标的ActionBar是半透明的,而且和一个大的图片集(一个大的杂志图标, ...

  8. Flare-On4 解题复现

    01 是一个 html 页面, 用开发者工具看看,发现是简单的 js 加密. 猜测加密算法可逆,试着用 PyvragFvqrYbtvafNerRnfl@syner-ba.pbz 作为输入,然后调试 , ...

  9. Android Studio 使用Intent实现页面的跳转(带参数)

    不管是在APP,还是在网站中,页面之间的跳转都是很常见的,本文主要讲一下在APP中,如何通过Intent实现页面的跳转. 不带参数: 写在MainActivity页面的代码: Intent inten ...

  10. Application Context的设计

    基本上每一个应用程序都会有一个自己的Application,并让它继承自系统的Application类,然后在自己的Application类中去封装一些通用的操作.其实这并不是Google所推荐的一种 ...