【CF809E】Surprise me!
这是一道神仙题
看到这样一个鬼畜的柿子
\]
又是树上距离又是\(\varphi\)的看起来根本就不知道怎么搞啊
首先需要知道一个这样的性质
\]
这个性质非常显然
设\(a=p^{k_1},b=p^{k_2},k_1<k_2\)
于是\(d=p^{k_1}\)
\]
\]
这个东西显然是积性的,扩展到多个质因子也是成立的
于是写成
\]
套路枚举\(gcd\)
\]
考虑设后面那个东西叫
\]
显然我们还需要一个函数叫
\]
我们可以直接反演了
\]
\]
现在的问题就是求出\(F\),我们就可以做了
显然树上的点都有一个约数\(d\)的时候,任意两点的的\(gcd\)就会是\(d\)的倍数
我们如果把\(d|a_i\)的\(i\)拿出来,建出一棵虚树,搞一个树形\(dp\)
求一下
\]
就好了,这就是一个小学生\(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!的更多相关文章
- 【CF809E】Surprise me!(动态规划,虚树,莫比乌斯反演)
[CF809E]Surprise me!(动态规划,虚树,莫比乌斯反演) 题面 洛谷 CodeForces 翻译: 给定一棵\(n\)个节点的树,每个点有一个权值\(a[i]\),保证\(a[i]\) ...
- 【CF809E】Surprise me! 树形DP 虚树 数学
题目大意 给你一棵\(n\)个点的树,每个点有权值\(a_i\),\(a\)为一个排列,求 \[ \frac{1}{n(n-1)}\sum_{i=1}^n\sum_{j=1}^n \varphi(a_ ...
- 【转】python f-string
[转]python f-string 文章目录 1. 主要内容 1.1. 旧时代的格式化字符串 1.1.1. Option #1: %-formatting 1.1.2. 怎样使用 %-forma ...
- 【Gabor】基于多尺度多方向Gabor融合+分块直方图的表情识别
Topic:表情识别Env: win10 + Pycharm2018 + Python3.6.8Date: 2019/6/23~25 by hw_Chen2018 ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
随机推荐
- Unity之使用技巧记录
A:写了个死循环Unity无响应崩溃了怎么办? Q::到文件夹里找到刚刚写的脚本,把错误的代码屏蔽掉,再回到Unity
- 适配器(GOF23)
---恢复内容开始--- 摘要:由于应用环境的变化,需要将现存的对象放到新的环境中去,但新环境的接口是现存对象不满足的. 意图:将原本接口不兼容的类通过转换,使得它们能够一起工作,复用现有的类 ada ...
- Linux学习6-Linux常用命令(2)
目录处理命令 命令名称:mkdir 命令英文原意:make directories 命令所在路径:/bin/mkdir 执行权限:所有用户 功能描述:创建新目录 语法:mkdir -p[目录名 ...
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
- 小程序视图层(xx.xml)和逻辑层(xx.js)
整个系统分为两块视图层(View)和逻辑层(App Service) 框架可以让数据与视图非常简单地保持同步.当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新. 通过这个简单的例子来 ...
- Laravel 支付宝异步通知 419报错
支付宝在支付是有服务器通知和网页通知,一个在前端展示,一个在后台操作, laravel框架自带csrf_token验证. 所以我们需要把支付的路由跳过验证 可以在中间键的csrf配置中更改
- GDAL线面互转换(2)
在上一个文章中介绍了线转化为面和面转化为线,其主要的实现思路就是把面中的点取出来构成线,把线中的点取出来构成面,实际上就是一个硬拷贝,无奈客户的实际需求并非如此,客户想要线转面的时候几条相交线构成面, ...
- Spring Boot—21Actuator--监控
https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/ pom.xml <dependency&g ...
- Eclipse 校验取消
eclipse Multiple annotations found at this line错误,eclipse开发过程中,一些XML配置文件会报错,但是这些其实不是错,飘红的原因是因为eclips ...
- Pig sample用法举例
some = sample data 0.1 遍历整个数据集,获取指定比例的行数的数据,获取的数据不确定,条数也不准确. 内部重写为filter data by random() <= ...