题解[T200448 Call of The Void]

题目链接

题意:

\(g(n)=\varphi(n)\sum\limits_{d^2|n}\mu(\frac{n}{d^2})\)\(\operatorname{dis}(x,y)=\prod\limits_{i\in path(x,y)}a_i\)

\(\prod\limits_{i=1}^{n}\prod\limits_{j=i+1}^{n}g(\operatorname{dis}(x,y))\)

\(\text{Part 1}\) : 推式子

首先那个 \(\sum\limits_{d^2|n}\mu(\frac{n}{d^2})\) 先可以化简:

\(\sum\limits_{d^2|n}\mu(\frac{n}{d^2})\)=\(\sum\limits_{d|n}\mu(\frac{n}{d})[d=k^2,k\in N^+]\)

卷积中的两个函数皆为积性函数,直接狄利克雷生成函数上:

\(=[n^{-z}]\left(\prod\limits_{p\in\text{Prime}}1-\dfrac{1}{p^z}\right)\left(\prod\limits_{p\in\text{Prime}}\sum\limits_{i\geq0}\dfrac{1}{p^{2iz}}\right)\)

\(=[n^{-z}]\left(\prod\limits_{p\in\text{Prime}}1-p^{-z}\right)\left(\prod\limits_{p\in\text{Prime}}\dfrac{1}{1-p^{-2z}}\right)\)

\(=[n^{-z}]\prod\limits_{p\in \text{Prime}}\dfrac{1}{1+p^{-z}}\)

\(=[n^{-z}]\prod\limits_{p\in\text{Prime}}\sum\limits_{i\geq0}\dfrac{(-1)^i}{p^{iz}}\)

所以可得 \(\sum\limits_{d^2|n}\mu(\frac{n}{d^2})=(-1)^{f(n)}\) 其中 \(f(n)\) 代表 \(n\) 的质因子次幂的和。

而这就是刘维尔函数,即 \(\sum\limits_{d^2|n}\mu(\frac{n}{d^2})=\lambda(n)\)

所以 \(g(n)=(-1)^{f(n)}\varphi(n)=(-1)^{f(n)}n\prod\limits_{p\in\text{Prime},p|n}1-\frac{1}{p}\)

由于 \((-1)^{f(n)}\)\(n\) 都是完全积性函数。

这两者只需统计出每个点有多少条路径经过,再快速幂计算贡献。

关键就是 \(\prod\limits_{p\in\text{Prime},p|n}1-\frac{1}{p}\)

由于最终的答案还要乘上所有不同路径的点权积的这个值的积。

可以考虑每个质数 \(p\) 在树中有多少条路径包含。

那每个 \(p\) 的贡献就是 \(1-\frac{1}{p}\) 的这个路径数次方。

这明摆着就是要建虚树求,考虑如何 \(\text{dp}\)

\(\text{Part 2}\) : \(\text{dp}\)

虚树上由关键点与辅助点构成,需分开讨论。

\(size(z)\)\(x\) 在原树上的子树大小。

再设 \(sz(x)=\text{x}\) 子树内离 \(\text{x}\) 最近的关键点的子树大小之和。

特别的,\(\text{x}\) 自己是关键点时 \(sz(x)\) 就是 \(size(x)\)

举个例子:

\(2,4,6,12,13\) 为关键点。

虚树上的点与其 \(sz\) 即为 \(sz_1=7,sz_2=3,sz_4=sz_7=2,sz_6=sz_{12}=sz_{13}=1\)

假定在 \(\text{dp}\) 时要处理出来以每个点为 \(lca\) 的路径个数,以及每个点到其虚树上的儿子上不在虚树中的点的贡献。

设当前处理的点为 \(x\)

\(x\) 为关键点

其子树内经过 \(x\) 的在其子树内的路径皆合法,这可以提前预处理出。

而对于它每个虚树上的儿子 \(y\)\(x\)\(y\) 上的不在虚树中的节点都能与 \(sz(y)\) 所代表的点产生贡献。

\(y\)\(x\) 在原树上 \(x\) 的儿子 \(z\) 中的子树, \(z\) 可以倍增求出。

则此部分贡献就是 \(sz(y)\times(size(z)-size(y))\)

\(x\) 为辅助节点

考虑每个 \(x\) 在树上的节点 \(y\)\(sz\) 能与其它点的贡献。

首先 \(sz(y)\) 能乘上搜到 \(y\) 之前全部子节点的 \(sz\) 和,明确搜到 \(y\) 之前是为了不算重。

这样算出来的路径上关键点个数都 \(\geq 2\)

除此之外,每个 \(sz(y)\) 还能与其他 \(x\) 子树中到 \(x\) 路径上无关键点的点产生贡献。

其为 \(v=size(x)-\sum\limits_{y\in son(x)}sz(y)\) ,此处 \(y\) 为虚树上 \(x\) 的儿子。

由于 \(size(y)-sz(y)\) 这些点理应在处理 \(y\) 时与 \(sz(y)\) 算过。

所以这部分贡献是 \(sz(y)\times (v-size(y)+sz(y))\)

时间复杂度

对于每个点的权值,会算其质因子个数次,虚树总点数约为 \(O(n\dfrac{\ln V}{\ln\ln V})\)

证明可参考 这里

再加上预处理以及建虚树、倍增的时间复杂度。

总时间复杂度为 \(O(V+n\log n\dfrac{\ln V}{\ln\ln V})\)

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,V=1e6,mod=998244353;
int n,m,x,y,z,tot,tt,l,dl,tp;char ch,lambda[V+10];
int a[N],fd[N],p[V+10],prm;ll res,ans,qres,v,inv[V+10],wp[V+10];
int to[N<<1],nextn[N<<1],h[N],edg;bool b[V+10],bb[N];
int dfn[N],tmp[N],st[N];int ff[N][20],dep[N];ll size[N],sz[N],sum[N];
int to1[N],nextn1[N],h1[V+10],edg1;
inline void read(int &x){
	x=0;ch=getchar();while(ch<48||ch>57)ch=getchar();
	while(ch>47&&ch<58)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
void write(int x){if(x>9)write(x/10);putchar(48+x%10);}
void init(){
	register int i,j;
	lambda[1]=1;
	for(i=2;i<=V;++i){
		if(!b[i])p[++prm]=i,lambda[i]=-1;
		for(j=1;j<=prm&&(x=i*p[j])<=V;++j){
			b[x]=1;
			lambda[x]=-lambda[i];
			if(i%p[j]==0)break;
		}
	}
	inv[1]=1;
	for(i=2;i<=V;++i)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(i=1;i<=prm;++i)wp[i]=(mod+1-inv[p[i]])%mod;
}
inline void qpow(ll x,ll k){
	qres=1;
	while(k){
		if(k&1)qres=qres*x%mod;
		x=x*x%mod;
		k>>=1;
	}
}
void init(int x,int anc){
	ll v=0;
	int i,y;dfn[x]=++tt;ff[x][0]=anc;dep[x]=dep[anc]+1;
	for(i=1;i^19;++i)ff[x][i]=ff[ff[x][i-1]][i-1];size[x]=1;
	for(i=h[x];y=to[i],i;i=nextn[i])if(y^anc){
		init(y,x);
		v+=size[x]*size[y];
		size[x]+=size[y];
	}
	sum[x]=v;
	v+=size[x]*(n-size[x]);
	h[x]=0;
	if(lambda[a[x]]^1&&v&1)res=mod-res;
	qpow(a[x],v);ans=ans*qres%mod;
}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline void lca(int x,int y){
	register int i;
	if(dep[x]<dep[y])x^=y^=x^=y;
	for(i=19;~i;--i)if(dep[ff[x][i]]>=dep[y])x=ff[x][i];
	if(x==y)l=x;
	else {
		for(i=19;~i;--i)if(ff[x][i]^ff[y][i])x=ff[x][i],y=ff[y][i];
		l=ff[x][0];
	}
}
inline void add(int x,int y){to[++edg]=y,nextn[edg]=h[x],h[x]=edg;}
inline void add1(int x,int y){to1[++edg1]=y,nextn1[edg1]=h1[x],h1[x]=edg1;}
void find(int x,int y){
	register int i;dl=dep[y]+1;
	for(i=19;~i;--i)if(dep[ff[x][i]]>=dl)x=ff[x][i];
	z=x;
}
void dfs(int x){
	int i,y;
	if(bb[x]){
		for(i=h[x];y=to[i],i;i=nextn[i]){
			dfs(y);find(y,x);
			res+=sz[y]*(size[z]-size[y]);
		}
		res+=sum[x];
		sz[x]=size[x];
	}
	else {
		sz[x]=0;ll v=0;
		for(i=h[x];y=to[i],i;i=nextn[i]){
			dfs(y);v+=sz[y];
			res+=sz[y]*sz[x];
			sz[x]+=sz[y];
		}
		v=size[x]-v;
		for(i=h[x];y=to[i],i;i=nextn[i])
			res+=sz[y]*(v-size[y]+sz[y]);
	}
	h[x]=0;
}
main(){
	read(n);register int i,j,k;init();
	for(i=1;i^n;++i)read(x),read(y),add(x,y),add(y,x);
	for(i=1;i<=n;++i)read(a[i]),add1(a[i],i);
	res=ans=1;init(1,0);edg=0;ll res1=1;
	ans=ans*res%mod;
	for(i=1;x=p[i],i<=prm;++i){
		tot=0;
		for(j=x;j<=V;j+=x)for(k=h1[j];k;k=nextn1[k])bb[tmp[++tot]=to1[k]]=1;
		if(tot){
			sort(tmp+1,tmp+tot+1,cmp);
			st[tp=1]=1;
			for(j=(tmp[1]==1)+1;x=tmp[j],j<=tot;++j){
				lca(x,z=st[tp]);dl=dfn[l];
				if(l^z){
					--tp;
					while(dfn[y=st[tp]]>dfn[l])add(y,z),z=y,--tp;
					add(l,z);if(l^y)st[++tp]=l;
				}
				st[++tp]=x;
			}
			z=st[tp];--tp;
			while(y=st[tp])add(y,z),z=y,--tp;
			res=0;dfs(1);
			qpow(wp[i],res);
			ans=ans*qres%mod;edg=0;
			for(j=1;j<=tot;++j)bb[tmp[j]]=0;
		}
	}
	write(ans);
}
posted @ 2021-09-24 22:15  Y_B_X  阅读(30)  评论(0编辑  收藏  举报