BSOJ5661题解

这题挺牛逼的,记录一下。

询问所有点分树的子树大小之和的期望。

众所周知子树大小之和等于每个节点的深度之和。

把深度考虑成有多少个节点是其祖先,利用期望的线性性可以拆开得到:\(E(x)=\sum_{u=1}^{n}\sum_{v=1}^{n}E(\texttt{u is v's grandfather})\)

考虑每一个 \(E\) 怎么求。将路径上的点拉出来,考虑建立点分树的过程,不难发现只需要 \(u\)\(u,v\) 这条路径上第一个被选的点即可。不管非路径点(对答案无影响),每个点被选到的概率相同,所以 \(E(\texttt{u is v's grandfather})=\frac{1}{dis(u,v)+1}\)

做一个点分治+NTT就可以了。

#include<cstdio>
#include<cctype>
#define IMP(lim,act) for(ui qwq=(lim),i=0;i^qwq;++i)act
typedef unsigned ui;
const ui M=30005,mod=998244353;
ui n,siz[M];bool vis[M];
ui buf[M<<3],*w[20];ui x,y,F[M<<2],G[M<<2],ans[M];
ui ege,h[M];ui rt,SZ;
struct Edge{
	ui v,nx;
}e[M<<1];
inline void AddEdge(const ui&u,const ui&v){
	e[++ege]=(Edge){v,h[u]};h[u]=ege;
	e[++ege]=(Edge){u,h[v]};h[v]=ege;
}
inline ui Getlen(const ui&n){
	ui len(0);while((1<<len)<n)++len;return len;
}
inline ui Add(const ui&a,const ui&b){
	return a>=mod-b?a+b-mod:a+b;
}
inline ui Del(const ui&a,const ui&b){
	return b>a?a-b+mod:a-b;
}
inline void swap(ui&a,ui&b){
	ui c=a;a=b;b=c;
}
inline ui pow(ui a,ui b=mod-2){
	ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
inline void init(const ui&n){
	const ui&m=Getlen(n);ui*now=buf;w[m]=now;now+=1<<m;
	w[m][0]=1;w[m][1]=pow(3,mod-1>>m+1);for(ui i=2;i^1<<m;++i)w[m][i]=1ull*w[m][i-1]*w[m][1]%mod;
	for(ui k=m-1;k<m&&(w[k]=now,now+=1<<k);--k)IMP(1<<k,w[k][i]=w[k+1][i<<1]);
}
inline void DFT(ui*f,const ui&M){
	const ui&n=1<<M;
	for(ui len=n>>1,d=M-1;d<M;--d,len>>=1){
		for(ui k=0;k^n;k+=len<<1){
			ui*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=*R)),*L++=Add(x,y),*R++=1ull**W++*Del(x,y)%mod;
		}
	}
}
inline void IDFT(ui*f,const ui&M){
	const ui&n=1<<M;
	for(ui len=1,d=0;d<M;++d,len<<=1){
		for(ui k=0;k^n;k+=len<<1){
			ui*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=1ull**W++**R%mod)),*L++=Add(x,y),*R++=Del(x,y);
		}
	}
	const ui&k=pow(n);IMP(n,f[i]=1ull*f[i]*k%mod);for(int i=1;(i<<1)<n;++i)swap(f[i],f[n-i]);
}
inline void init(const ui&u,const ui&fa){
	siz[u]=1;for(ui v,E=h[u];E;E=e[E].nx)if(v=e[E].v,v^fa&&!vis[v])init(v,u),siz[u]+=siz[v];
}
inline void FR(const ui&u,const ui&fa,const ui&S){
	ui mx(S-siz[u]);for(ui v,E=h[u];E;E=e[E].nx)if(v=e[E].v,v^fa&&!vis[v])FR(v,u,S),siz[v]>mx&&(mx=siz[v]);
	if(mx<SZ)SZ=mx,rt=u;
}
inline void DFS(const ui&u,const ui&dep,const ui&fa){
	if(dep>y)y=dep;++G[dep];for(ui v,E=h[u];E;E=e[E].nx)if(v=e[E].v,v^fa&&!vis[v])DFS(v,dep+1,u);
}
inline void Solve(const ui&u){
	vis[u]=true;
	for(ui v,E=h[u];E;E=e[E].nx)if(!vis[v=e[E].v]){
		DFS(v,1,u);if(y>x)x=y;for(ui i=1;i<=y;++i)F[i]+=G[i],ans[i]+=G[i]<<1;
		const ui&m=Getlen(y+1)+1;DFT(G,m);IMP(1<<m,G[i]=1ull*G[i]*G[i]%mod);IDFT(G,m);
		for(ui i=2;i<=(y<<1);++i)ans[i]-=G[i],G[i]=0;y=0;
	}
	const ui&m=Getlen(x+1)+1;DFT(F,m);IMP(1<<m,F[i]=1ull*F[i]*F[i]%mod);IDFT(F,m);
	for(ui i=2;i<=(x<<1);++i)ans[i]+=F[i],F[i]=0;x=0;
	for(ui v,E=h[u];E;E=e[E].nx)if(!vis[v=e[E].v]){
		init(v,u);SZ=0x7fffffff;FR(v,u,siz[v]);Solve(rt);
	}
}
inline ui read(){
	ui n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
signed main(){
	double res(0);n=read();res=n;init(n<<1);for(ui u,v,i=1;i<n;++i)u=read(),v=read(),AddEdge(++u,++v);
	init(1,0);SZ=0x7fffffff;FR(1,0,n);Solve(rt);for(ui i=1;i<=n;++i)res+=1.*ans[i]/(i+1);printf("%.4lf",res);
}
posted @ 2022-06-24 09:17  Prean  阅读(23)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};