题目链接

\(Description\)

  给定一棵树,求$$\frac{1}{n(n-1)/2}\times\sum_{i\in[1,n],j\in[1,n],i\neq j}\varphi(a_i\times a_j)\times dis(i,j)\ \ \ \ (mod\ 10^9+7)$$

  其中\(a_i\)是\([1,n]\)的一个排列,两两不同。

\(Solution\)

  前面直接最后乘逆元就可以。看后面的\(\sum\)怎么化。

  要想办法把\(\varphi(a_i\times a_j)\)化掉。

  考虑\(\varphi\)的定义式:\(\varphi(n)=n\times\prod_{i=1}^k(1-\frac{1}{p_i})\)

  \(\varphi(a_i)=a_i\times\prod_{l=1}^k(1-\frac{1}{p_l})\)

  \(\varphi(a_j)=a_j\times\prod_{l=1}^{k'}(1-\frac{1}{p'_l})\)

  两者相乘的话会多算\(g=\gcd(a_i,a_j)\)的\(\prod_{l=1}^{k''}(1-\frac{1}{p''_l})\)部分。所以有:$$\varphi(a\times b)=\varphi(a)\times\varphi(b)\times\frac{\gcd(a,b)}{\varphi(\gcd(a,b))}$$

  \(\sum\)就可以化成上面那种形式。

  带着\(\gcd(a,b)\),想到去枚举\(d=\gcd(a,b)\),于是$$原式=\sum_{d=1}n\frac{d}{\varphi(d)}\sum_{i=1}n\sum_{j=1}^n\varphi(a_i)\varphi(a_j)dis(i,j)[\gcd(a_i,a_j)=d]$$

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

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

  那么要求的$$f(d)=\sum_{d\mid n}\mu(\frac{n}{d})F(n)=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)F(id)$$

  如果能求出\(F(id)\),那么答案就可以在\(O(n\ln n)\)时间内得到了。

  \(F(d)\)中要求\(d\mid\gcd(a_i,a_j)\),那么只有\(d\mid a_i\)的点之间才会产生贡献,于是我们可以建虚树。\(d\)最大是\(n\),总点数是\(n\ln n\)的。

  现在考虑如何在虚树上求答案。\(dis(i,j)\)可以拆掉,写成:\(dep(i)+dep(j)-2*dep(lca(i,j))\)

  现在$$F(d)=\sum_{1\leq i\leq n,d\mid a_i}\sum_{1\leq j\leq n,d\mid a_j}\varphi(a_i)\varphi(a_j)[dep(i)+dep(j)-dep(lca(i,j))]$$

  \(dep(i)\)和\(dep(j)\)可以在处理\(i,j\)时分别直接算出来,现在要算$$-2\times\sum_{1\leq i\leq n,d\mid a_i}\sum_{1\leq j\leq n,d\mid a_j}\varphi(a_i)\varphi(a_j)dep(lca(i,j))$$

  枚举lca,求其子树\(\varphi\)的和就行了。

  构建虚树时 按照DFS序存下每个点,这样就可以省掉排序了。


  改了一个小时的MLE,发现:为什么数组开小MLE了==?而且N至少是3e5不能是2e5why。。


//1107ms	75700KB
#include <cmath>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define pb push_back
#define Vec std::vector<int>
#define mod (1000000007)
#define Add(x,v) (x)+=(v),(x)>=mod&&((x)-=mod)
typedef long long LL;
const int N=300005;//2e5+5??? int n,A[N],Enum,H[N],nxt[N<<1],to[N<<1],dfn[N],Index,fa[N],sz[N],dep[N],son[N],tp[N],sk[N],top;
int cnt,P[N],phi[N],mu[N],sum[N],f[N],inv[N];
bool not_P[N];
Vec fac[N],pt[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void Add_direct(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
}
inline void AddEdge(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline int LCA(int u,int v)
{
while(tp[u]!=tp[v]) dep[tp[u]]>dep[tp[v]]?u=fa[tp[u]]:v=fa[tp[v]];
return dep[u]>dep[v]?v:u;
}
void Pre()
{
mu[1]=phi[1]=1;
for(int i=2; i<=n; ++i)
{
if(!not_P[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
for(int j=1,v; j<=cnt&&(v=i*P[j])<=n; ++j)
{
not_P[v]=1;
if(i%P[j]) mu[v]=-mu[i], phi[v]=phi[i]*(P[j]-1);
else {mu[v]=0, phi[v]=phi[i]*P[j]; break;}
}
}
for(int i=1; i<=n; ++i)
for(int j=i; j<=n; j+=i) fac[j].push_back(i);
inv[1]=1;
for(int i=2; i<=n; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
void preDFS1(int x)
{
const Vec &fc=fac[A[x]];
for(int i=0,l=fc.size(); i<l; ++i) pt[fc[i]].push_back(x);
int mx=0; sz[x]=1, dfn[x]=++Index;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, preDFS1(v), sz[x]+=sz[v];
if(sz[v]>mx) mx=sz[v], son[x]=v;
}
}
void preDFS2(int x,int _tp)
{
tp[x]=_tp;
if(son[x])
{
preDFS2(son[x],_tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=son[x]&&to[i]!=fa[x]) preDFS2(to[i],to[i]);
}
}
void Insert(int x)
{
if(top==1) {sk[++top]=x; return;}
int lca=LCA(x,sk[top]);
while(dfn[sk[top-1]]>=dfn[lca]) Add_direct(sk[top],sk[top--]);
if(sk[top]!=lca) Add_direct(lca,sk[top]), sk[top]=lca;
sk[++top]=x;
}
void Build(const Vec &p)
{
int n=p.size();
sk[top=1]=1;
if(p[0]==1) for(int i=1; i<n; ++i) Insert(p[i]);
else for(int i=0; i<n; ++i) Insert(p[i]);
while(--top) Add_direct(sk[top],sk[top+1]);
}
LL DFS(int x,int d)//虚树上有其它的点!
{
LL res1=0, res2=0, s=A[x]%d?0:phi[A[x]];
for(int v,i=H[x]; i; i=nxt[i])
res1+=DFS(v=to[i],d), res2+=1ll*s*sum[v]%mod, Add(s,sum[v]);
sum[x]=s%mod, H[x]=0;//!
return (res1%mod+res2*(LL)dep[x]%mod)%mod;//子树的答案和当前点为LCA独立,别算在一块。。
}
void Calc(int d)
{
const Vec &p=pt[d];
// if(!p.size()) return;
Build(p);
LL res=0, sum=0; int n=p.size();
for(int i=0; i<n; ++i) if(!(A[p[i]]%d)) sum+=phi[A[p[i]]];
sum%=mod;
for(int i=0; i<n; ++i) if(!(A[p[i]]%d)) res+=1ll*phi[A[p[i]]]*(sum-phi[A[p[i]]])%mod*dep[p[i]]%mod;
res%=mod, res-=2ll*DFS(1,d)%mod;
f[d]=(res%mod+mod)%mod;//+mod!
Enum=0;
} int main()
{
n=read();
for(int i=1; i<=n; ++i) A[i]=read();
for(int i=1; i<n; ++i) AddEdge(read(),read());
Pre(), preDFS1(1), preDFS2(1,1);
memset(H,0,sizeof H);
for(int i=1; i<=n; ++i) Calc(i);
LL ans=0;
for(int d=1; d<=n; ++d)
{
LL sum=0;
for(int i=1; i*d<=n; ++i) sum+=mu[i]*f[i*d];
ans+=1ll*(sum%mod)*d%mod*inv[phi[d]]%mod;
}
printf("%I64d\n",2ll*(ans%mod)*inv[n]%mod*inv[n-1]%mod); return 0;
}

Codeforces.809E.Surprise me!(莫比乌斯反演 虚树)的更多相关文章

  1. Codeforces 809E Surprise me! [莫比乌斯反演]

    洛谷 Codeforces 非常套路的一道题,很适合我在陷入低谷时提升信心-- 思路 显然我们需要大力推式子. 设\(p_{a_i}=i\),则有 \[ \begin{align*} n(n-1)an ...

  2. 【Codeforces 809E】Surprise me!(莫比乌斯反演 & 虚树)

    Description 给定一颗 \(n\) 个顶点的树,顶点 \(i\) 的权值为 \(a_i\).求: \[\frac{1}{n(n-1)}\sum_{i=1}^n\sum_{j=1}^n\var ...

  3. YbtOJ#723-欧拉之树【莫比乌斯反演,虚树】

    正题 题目链接:http://www.ybtoj.com.cn/contest/121/problem/2 题目大意 给出\(n\)个点的一棵树,每个点有一个权值\(a_i\),求 \[\sum_{i ...

  4. 【BZOJ3529】数表(莫比乌斯反演,树状数组)

    [BZOJ3529]数表(莫比乌斯反演,树状数组) 题解 首先不管\(A\)的范围的限制 要求的东西是 \[\sum_{i=1}^n\sum_{j=1}^m\sigma(gcd(i,j))\] 其中\ ...

  5. 【bzoj3529】[Sdoi2014]数表 莫比乌斯反演+离线+树状数组

    题目描述 有一张n×m的数表,其第i行第j列(1 <= i <= n ,1 <= j <= m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. ...

  6. Codeforces 809E - Surprise me!(虚树+莫比乌斯反演)

    Codeforces 题目传送门 & 洛谷题目传送门 1A,就 nm 爽( 首先此题一个很棘手的地方在于贡献的计算式中涉及 \(\varphi(a_ia_j)\),而这东西与 \(i,j\) ...

  7. CF809E Surprise me! 莫比乌斯反演、虚树

    传送门 简化题意:给出一棵\(n\)个点的树,编号为\(1\)到\(n\),第\(i\)个点的点权为\(a_i\),保证序列\(a_i\)是一个\(1\)到\(n\)的排列,求 \[ \frac{1} ...

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

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

  9. CodeCraft-19 and Codeforces Round #537 (Div. 2) E 虚树 + 树形dp(新坑)

    https://codeforces.com/contest/1111/problem/E 题意 一颗有n个点的树,有q个询问,每次从树挑出k个点,问将这k个点分成m组,需要保证在同一组中不存在一个点 ...

随机推荐

  1. PHP验证注册信息

    注册页面reg.html <form action="reg.php" method="post"> 用户名<input type=" ...

  2. java所搜引擎slor学习笔记(一)

    java搜索引擎有很多,比较熟悉的就是slor和lucene. luncene: 概念:全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置.当用户查 ...

  3. gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化【转】

    转自:http://blog.csdn.net/qinrenzhi/article/details/78334677 相关博客http://blog.chinaunix.net/uid-2495495 ...

  4. python面向对象(七)属性方法的添加

    ​ 通常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.下来我就讲下添加属性和方法,同时也将下限值添加属性方法. 添加属性 ...

  5. JQuery中DOM事件合成用法

    jQuery有两个合成事件——hover()方法和toggle()方法 类似前面讲过的ready()方法,hover()方法和toggle()方法都属于jQuery自定义的方法. hover()方法: ...

  6. 浅谈js设计模式之策略模式

    策略模式有着广泛的应用.本节我们就以年终奖的计算为例进行介绍. 很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的.例如,绩效为 S的人年终奖有 4倍工资,绩效为 A的人年终奖有 3倍工资,而 ...

  7. 高版本SQL备份在低版本SQL还原问题

    问题描述: 高版本SQL备份在低版本SQL还原问题(出现媒体簇的结构不正确)      分析原因: SQL版本兼容问题,SQL SERVER兼容级别是用作向下兼容用,高版本的SQL备份在低版本中不兼容 ...

  8. CVE-2009-3459

     Adobe Acrobat和Reader都是美国Adobe公司开发的非常流行的PDF文件阅读器.         Adobe Reader和Acrobat 7.1.4之前的7.x版本,8.1.7之前 ...

  9. SSIS 学习之旅 FTP文件传输-FTP任务

    这一章主要讲解一下FTP控件. 设计:   通过Demon库的Users表数据生成CSV文件.   生成后的CSV文件抛送到FTP指定目录下. 其他控件的使用这里就不做详细讲解了.大家如果有不懂得可以 ...

  10. 为django平台生成模拟用户,建立用户组,并将用户加入组

    书接上篇BLOG. 当我们可以用manage.py自定义命令来生成模拟数据时, 我们面对的就是如何操作ORM的问题了. 这两天,我为我们的内部系统的所有数据表,都生成了模拟数据. 有几个心得,记录于此 ...