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);
}