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

题面

洛谷

CodeForces

翻译:

给定一棵\(n\)个节点的树,每个点有一个权值\(a[i]\),保证\(a[i]\)是一个\(1..n\)的排列。

求$$\frac{1}{n(n-1)}\sum_{i=1}n\sum_{j=1}n\varphi(a_i*a_j)·dist(i,j)$$

其中,\(\varphi(x)\)是欧拉函数,\(dist(i,j)\)表示\(i,j\)两个节点在树上的距离。

题解

神题啊。。。

首先来个轻松而有趣的结论

\(\varphi(a*b)=\varphi(a)*\varphi(b)*\frac{d}{\varphi(d)}\),其中,\(d=gcd(a,b)\)

证明?大力分解质因数就好啦

现在我们来推式子(好久没有推过式子啦)

先不管前面那个东西

\[\begin{aligned}
Ans&=\sum_{i=1}^n\sum_{j=1}^n\varphi(a_i)\varphi(a_j)\frac{gcd(a_i,a_j)}{\varphi(gcd(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)\\
\end{aligned}
\]

这样的东西很舒服啊

设$$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)$$

然后莫比乌斯反演就可以用啦

\[g(d)=\sum_{d|i}\mu(\frac{i}{d})f(i)
\]

现在只需要求解\(f(i)\)

接着推式子

\[\begin{aligned}Ans&=\sum_{d=1}^n\frac{d}{\varphi(d)}g(d)\\
&=\sum_{d=1}^n\frac{d}{\varphi(d)}\sum_{d|i}\mu(\frac{i}{d})f(i)\\
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_{i=1}^n\sum_{j=1}^n[d|gcd(a_i,a_j)]\varphi(a_i)\varphi(a_j)(dep_i+dep_j-2*dep_{lca})
\end{aligned}
\]

我们发现,对于\(d|gcd(a_i,a_j)\)的所有\(i,j\)

相当于满足\(a_i,a_j\)是\(d\)的倍数

如果只是求前面的两项只与自身有关的\(dep_i+dep_j\),

这个问题就非常好解。

但是现在多了一个\(dep_{lca}\) 。

因此我们需要做\(dp\)。

把所有\(d|a_i\)的点全部拿下来建立虚树,在虚树上\(dp\)就好了。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 222222
#define MOD 1000000007
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int a[MAX],b[MAX],n;
int phi[MAX],mu[MAX],pri[MAX],tot;
bool zs[MAX];
void pre(int N)
{
zs[1]=true;phi[1]=mu[1]=1;
for(int i=2;i<=N;++i)
{
if(!zs[i])pri[++tot]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=tot&&i*pri[j]<=N;++j)
{
zs[i*pri[j]]=true;
if(i%pri[j])phi[i*pri[j]]=phi[i]*phi[pri[j]],mu[i*pri[j]]=-mu[i];
else{mu[i*pri[j]]=0,phi[i*pri[j]]=phi[i]*pri[j];break;}
}
}
}
int dfn[MAX],low[MAX],size[MAX],hson[MAX],top[MAX],fa[MAX],tim,dep[MAX];
void dfs1(int u,int ff)
{
fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;dfn[u]=++tim;
if(hson[u])dfs2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=fa[u]&&e[i].v!=hson[u])
dfs2(e[i].v,e[i].v);
low[u]=tim;
}
int LCA(int u,int v)
{
while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int ans=0,K,p[MAX<<1],S[MAX],f[MAX];
bool vis[MAX];
void Plus(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
void DP(int u)
{
f[u]=vis[u]?phi[a[u]]:0;
Plus(ans,MOD-1ll*f[u]*f[u]%MOD*dep[u]%MOD);
for(int i=h[u];i;i=e[i].next)
{
DP(e[i].v);
Plus(ans,MOD-2ll*f[u]*f[e[i].v]%MOD*dep[u]%MOD);
Plus(f[u],f[e[i].v]);
}
}
int F[MAX],G[MAX];
int main()
{
n=read();pre(n);
for(int i=1;i<=n;++i)a[i]=read(),b[a[i]]=i;
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
dfs1(1,0);dfs2(1,1);
memset(h,0,sizeof(h));
for(int T=1;T<=n;++T)
{
K=n/T;int s1=0,s2=0;cnt=1;
for(int i=1;i<=K;++i)p[i]=b[i*T];
for(int i=1;i<=K;++i)
Plus(s1,phi[a[p[i]]]),Plus(s2,1ll*dep[p[i]]*phi[a[p[i]]]%MOD);
for(int i=1;i<=K;++i)vis[p[i]]=true;
sort(&p[1],&p[K+1],cmp);
for(int i=K;i>1;--i)p[++K]=LCA(p[i],p[i-1]);
sort(&p[1],&p[K+1],cmp);K=unique(&p[1],&p[K+1])-p-1;
for(int i=1,tp=0;i<=K;++i)
{
while(tp&&low[S[tp]]<dfn[p[i]])--tp;
Add(S[tp],p[i]);S[++tp]=p[i];
}
DP(p[1]);Plus(ans,ans);
Plus(ans,2ll*s1*s2%MOD);
for(int i=1;i<=K;++i)h[p[i]]=0,vis[p[i]]=false;
F[T]=ans;ans=0;
}
for(int i=1;i<=n;++i)
for(int j=i;j<=n;j+=i)
if(mu[j/i]!=0)Plus(G[i],(mu[j/i]==1)?F[j]:(MOD-F[j]));
for(int i=1;i<=n;++i)G[i]=1ll*G[i]*i%MOD*fpow(phi[i],MOD-2)%MOD;
for(int i=1;i<=n;++i)Plus(ans,G[i]);
ans=1ll*ans*fpow(n,MOD-2)%MOD*fpow(n-1,MOD-2)%MOD;
printf("%d\n",ans);
return 0;
}

【CF809E】Surprise me!(动态规划,虚树,莫比乌斯反演)的更多相关文章

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

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

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

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

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

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

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

    题目链接 \(Description\) 给定一棵树,求\[\frac{1}{n(n-1)/2}\times\sum_{i\in[1,n],j\in[1,n],i\neq j}\varphi(a_i\ ...

  5. CF809E Surprise me!(莫比乌斯反演+Dp(乱搞?))

    题目大意: 给你一棵树,树上的点编号为\(1-n\).选两个点\(i.j\),能得到的得分是\(\phi(a_i*a_j)*dis(i,j)\),其中\(dis(i,j)\)表示\(a\)到\(b\) ...

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

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

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

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

  8. bzoj3529(莫比乌斯反演+离线+树状数组)

    在你以为理解mobus的时候,苦苦想通过化简公式来降低复杂度时,这题又打了我一巴掌. 看来我并没有理解到acmicpc比赛的宗旨啊. 这么多次查询可以考虑离线操作,使用树状数组单点更新. /***** ...

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

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

随机推荐

  1. 复习C#的方法Math.Max和Math.Min

    温故而知新,今天学习Math.Max和Min的方法.这2个方法,均需要传入2个参数,返回参数中最大值和最小值. class Ac { public void LeanMathFunction() { ...

  2. C#深入理解AutoResetEvent和ManualResetEvent

    当在C#使用多线程时就免不了使用AutoResetEvent和ManualResetEvent类,可以理解这两个类可以通过设置信号来让线程停下来或让线程重新启动,其实与操作系统里的信号量很相似(汗,考 ...

  3. Luogu P2257 YY的GCD

    莫比乌斯反演第一题.莫比乌斯反演入门 数论题不多BB,直接推导吧. 首先,发现题目所求\(ans=\sum_{i=1}^n\sum_{j=1}^m [\gcd(i,j)=prime]\) 考虑反演,我 ...

  4. 2-SAT超入门讲解

    Preface 说实话2-SAT的题目我都没怎么做过,所以这里讲的都是些超入门什么的 还有一些板子题,由于是暑假的时候学的所以有些我也记不清了 主要学习参考自:Mancher的课件&& ...

  5. Codeforces 987E Petr and Permutations(数组的置换与复原 、结论)

    题目连接: Petr and Permutations 题意:给出一个1到n的序列,Petr打乱了3n次,Um_nik打乱了7n+1次,现在给出被打乱后的序列,求是谁打乱的. 题解:因为给出了一个3* ...

  6. 记一次MongoDB裸奔

    导言 大意失荆州,裸奔的 MongoDB 被黑了.虽然并不是什么非常重要的数据,但也给自己敲响的一个警钟.虽然我们平时不容易接触到数据安全,但我们在开发,部署项目的时候,一定要养成良好的安全意识. 根 ...

  7. 【C++】std::是什么?

    引例: #include<iostream> int main() { std::cout<<"我喜欢C++";//输出一句话 std::cout<& ...

  8. Flutter - TabBar导航栏切换后,状态丢失

    上一篇讲到了 Flutter - BottomNavigationBar底部导航栏切换后,状态丢失 里面提到了TabBar,这儿专门再写一下吧,具体怎么操作,来不让TabBar的状态丢失.毕竟大家99 ...

  9. 从源码的角度看 React JS 中批量更新 State 的策略(下)

    这篇文章我们继续从源码的角度学习 React JS 中的批量更新 State 的策略,供我们继续深入学习研究 React 之用. 前置文章列表 深入理解 React JS 中的 setState 从源 ...

  10. Elasticsearch学习总结 (Centos7下Elasticsearch集群部署记录)

    一.  ElasticSearch简单介绍 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticse ...