【CF809E】Surprise me!(莫比乌斯反演)(虚树)(树形DP)

传送门


题解:

前面那个关于 n n n的式子丢掉不管。

首先我们可以魔改树的标号使得我们需要求的式子变成下面这个:

A n s = ∑ i = 1 n ∑ j = 1 n ϕ ( i j ) d i s t ( i , j ) Ans=\sum_{i=1}^n\sum_{j=1}^n\phi(ij)dist(i,j) Ans=i=1nj=1nϕ(ij)dist(i,j)

对于欧拉函数,有: ϕ ( i j ) = ϕ ( i ) ϕ ( j ) g c d ( i , j ) ϕ ( g c d ( i , j ) ) \phi(ij)=\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))} ϕ(ij)=ϕ(gcd(i,j))ϕ(i)ϕ(j)gcd(i,j)

则莫比乌斯反演结果为:

A n s = ∑ T = 1 n ∑ d ∣ T d μ ( T d ) ϕ ( d ) ∑ i = 1 ⌊ n T ⌋ ∑ j = 1 ⌊ n T ⌋ ϕ ( i T ) ϕ ( j T ) d i s t ( i T , j T ) Ans=\sum_{T=1}^n\sum_{d\mid T}\frac{d\mu(\frac{T}{d})}{\phi(d)}\sum_{i=1}^{\lfloor\frac{n}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{T}\rfloor}\phi(iT)\phi(jT)dist(iT,jT) Ans=T=1ndTϕ(d)dμ(dT)i=1Tnj=1Tnϕ(iT)ϕ(jT)dist(iT,jT)

g ( n ) = ∑ d ∣ n d μ ( n d ) ϕ ( d ) g(n)=\sum_{d\mid n}\frac{d\mu(\frac{n}{d})}{\phi(d)} g(n)=dnϕ(d)dμ(dn),则 g g g可以在 O ( n log ⁡ n ) O(n\log n) O(nlogn)时间内处理完毕。

枚举所有的 T T T,则还剩下一个问题:如何求 ∑ i = 1 ⌊ n T ⌋ ∑ j = 1 ⌊ n T ⌋ ϕ ( i T ) ϕ ( j T ) d i s t ( i T , j T ) \sum_{i=1}^{\lfloor\frac{n}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{T}\rfloor}\phi(iT)\phi(jT)dist(iT,jT) i=1Tnj=1Tnϕ(iT)ϕ(jT)dist(iT,jT)

实际上建完虚树后就是求 ∑ i ∑ j v a l i v a l j d i s t ( i , j ) \sum_{i}\sum_{j}val_ival_jdist(i,j) ijvalivaljdist(i,j)

这个东西随便搞一个 O ( n ) O(n) O(n)的树形DP就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;
		while(!isdigit(c=gc()));T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}

cs int P=2e5+5;
int phi[P],mu[P],inv[P],g[P];
int prime[P],pcnt;
bool mark[P];

inline void linear_sieves(int len){
	phi[1]=mu[1]=inv[1]=inv[0]=1;
	for(int re i=2;i<=len;++i){
		inv[i]=mul(inv[mod%i],mod-mod/i);
		if(!mark[i])prime[++pcnt]=i,phi[i]=i-1,mu[i]=mod-1;
		for(int re j=1;i*prime[j]<=len;++j){
			mark[i*prime[j]]=true;
			if(i%prime[j]){
				phi[i*prime[j]]=phi[i]*(prime[j]-1);
				Dec(mu[i*prime[j]],mu[i]);
			}
			else {
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
		}
	}
	for(int i=1;i<=len;++i){
		for(int re j=i,k=1,t=mul(i,inv[phi[i]]);j<=len;j+=i,++k)
		Inc(g[j],mul(t,mu[k]));
	}
}

cs int N=2e5+5;

int n;

std::vector<int> G[N];
inline void addedge(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
}

namespace ST{
	int st[20][N<<1],dep[N],clk;
	int Log[N<<1],in[N],out[N];
	
	void dfs(int u,int pa){
		dep[u]=dep[pa]+1;
		st[0][in[u]=++clk]=u;
		for(int re v:G[u])if(v!=pa){
			dfs(v,u);
			st[0][++clk]=u;
		}out[u]=clk;
	}
	
	inline void init(){
		dfs(1,0);Log[0]=-1;
		for(int re i=1;i<=clk;++i)Log[i]=Log[i>>1]+1;
		for(int re i=1;(1<<i)<=clk;++i)
		for(int re j=1;j+(1<<i)-1<=clk;++j)
		st[i][j]=dep[st[i-1][j]]<dep[st[i-1][j+(1<<i-1)]]?st[i-1][j]:st[i-1][j+(1<<i-1)];
	}
	
	inline int LCA(int u,int v){
		int l=in[u],r=in[v];
		if(l>r)std::swap(l,r);
		int t=Log[r-l+1];
		return dep[st[t][l]]<dep[st[t][r-(1<<t)+1]]?st[t][l]:st[t][r-(1<<t)+1];
	}
	inline int dist(int u,int v){return dep[u]+dep[v]-(dep[LCA(u,v)]<<1);}
}
using ST::LCA;
using ST::dist;
using ST::in;
using ST::out;
using ST::dep;

int id[N],cnt;
int val[N];

namespace VT{
	struct edge{
		int to,w;
		edge(int _to,int _w):to(_to),w(_w){}
	};
	std::vector<edge> G[N];
	
	int st[N],top;
	
	inline void ins(int u){
		if(!top){st[++top]=u;return ;}
		int v=LCA(u,st[top]);
		while(top&&dep[st[top-1]]>dep[v]){
			G[st[top-1]].push_back(edge(st[top],dist(st[top-1],st[top])));
			--top;
		}
		if(dep[v]<dep[st[top]]){
			G[v].push_back(edge(st[top],dist(v,st[top])));
			--top;
		}
		if(!top||dep[st[top]]<dep[v])st[++top]=v;
		st[++top]=u;
	}
	
	int path[N],ans[N],sum[N];
	
	void dp(int u,int pa){
		path[u]=ans[u]=0;sum[u]=val[u];val[u]=0;
		for(auto &e:G[u]){
			int v=e.to;
			dp(v,u);
			Inc(ans[u],ans[v]);
			Inc(ans[u],mul(sum[v],path[u]));
			Inc(ans[u],mul(sum[u],path[v]));
			Inc(ans[u],mul(e.w,mul(sum[u],sum[v])));
			Inc(sum[u],sum[v]);
			Inc(path[u],path[v]);
			Inc(path[u],mul(sum[v],e.w));
		}
		G[u].clear();
	}
	
	inline int solve(){
		std::sort(id+1,id+cnt+1,[](int u,int v){return in[u]<in[v];});
		top=0;if(id[1]!=1)st[top=1]=1;
		for(int re i=1;i<=cnt;++i)ins(id[i]);
		while(top>1){
			int u=st[top],v=st[--top];
			G[v].push_back(edge(u,dist(u,v)));
		}
		dp(1,0);
		return ans[1];
	}
}

signed main(){
//	freopen("surprise.in","r",stdin);
	n=getint();linear_sieves(n);
	for(int re i=1;i<=n;++i)id[i]=getint();
	for(int re i=1;i<n;++i)addedge(id[getint()],id[getint()]);
	ST::init();
	int ans=0;
	for(int re i=1,lim=n>>1;i<=lim;++i){
		cnt=0;
		for(int re j=i;j<=n;j+=i)
		id[++cnt]=j,val[j]=phi[j];
		Inc(ans,mul(g[i],VT::solve()));
	}
	cout<<power(mul(n,n-1),mod-2,add(ans,ans))<<"\n";
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值