抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

此题恶臭,心态被搞了。

考虑SolveSolve算法,每个点有且仅有一次被当做树的根,于是可以将整个算法的期望时间复杂度变成每个点的树的期望大小之和。

想到这里,你还得有一个更加恶臭的想法,考虑如何表示每个点的树的期望大小,记p[i][j]p[i][j]jjii子树里面的概率。

那么ii子树的期望大小即是j!=ip[i][j]\sum _{j!=i} p[i][j]

如何计算p[i][j]p[i][j],考虑iijj的路径上共dis(i,j)+1dis(i,j)+1个点,只有ii是第一个被选择的点时,iijj才不会被分开,于是p[i][j]=1dis(i,j)+1p[i][j]=\frac{1}{dis(i,j)+1}。\dfrac

如何计算\sum _{i=1}^n \sum _{j=1} ^n \f\dfrac}{dis(i,j)+1}

我们转换一下,假设等于kkdis(i,j)dis(i,j)cnt[k]cnt[k]个,答案即是$\sum cnt[k] \times \frac{1}{k+\dfrac

这个cnt[k]cnt[k]可以FFTFFT+点分治去做。

考虑求出过当前树的根节点的路径数,设生成函数F(x)=i=0dep(i)xiF(x)=\sum _{i=0}^\infty dep(i) x^i。其中dep(i)dep(i)代表深度为ii的节点个数。

F(x)2=i=0(j=0idep(j)dep(ij))xiF(x)^2=\sum _{i=0}^\infty (\sum _{j=0}^i dep(j) dep(i-j)) x^i,即是i=0route(i)xi\sum _{i=0}^\infty route(i) x^i,其中route(i)route(i)代表路径个数。

这样算可能会有重复,于是按照点分治的套路需要容斥一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <bits/stdc++.h>
#define MAXN 500005
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
const double PI=acos(-1.0);
struct Complex{
double x,y;
};
inline Complex operator + (const Complex &A,const Complex &B){
return Complex{A.x+B.x,A.y+B.y};
}
inline Complex operator - (const Complex &A,const Complex &B){
return Complex{A.x-B.x,A.y-B.y};
}
inline Complex operator * (const Complex &A,const Complex &B){
return Complex{A.x*B.x-A.y*B.y,A.x*B.y+A.y*B.x};
}
Complex A[MAXN];
int r[MAXN];
inline void FFT(Complex *A,int n,int type){
for (register int i=0;i<n;++i) if (i<r[i]) swap(A[i],A[r[i]]);
for (register int i=1;i<n;i<<=1){
int R=i<<1;
Complex Wn=Complex{cos(2*PI/R),type*sin(2*PI/R)};
for (register int j=0;j<n;j+=R){
Complex w=Complex{1,0};
for (register int k=0;k<i;++k,w=w*Wn){
Complex x=A[j+k],y=w*A[i+j+k];
A[j+k]=x+y,A[i+j+k]=x-y;
}
}
}
if (type==-1){
for (register int i=0;i<n;++i) A[i].x/=(double)n;
}
}
int d[MAXN],ret[MAXN],ans[MAXN],sz;
inline void Mul(int f){
int m=1,L=0;
while (m<=2*sz) m<<=1,L++;
for (register int i=0;i<=m;++i){
r[i]=r[i>>1]>>1|((i&1)<<(L-1));
}
FFT(A,m,1);
for (register int i=0;i<m;++i) A[i]=A[i]*A[i];
FFT(A,m,-1);
for (register int i=0;i<=sz*2;++i) ans[i]+=f*(int)(A[i].x+0.5);//深度可能变成两倍(恶臭)
for (register int i=0;i<=m;++i) A[i].x=0,A[i].y=0;
}

vector<int>G[MAXN];
inline void AddEdge(int u,int v){
G[u].push_back(v);
}
int dp[MAXN],max_dp[MAXN],vis[MAXN],tot,root;
inline void InitDP(int u,int father){
dp[u]=1,max_dp[u]=0;
for (register int i=0;i<(int)G[u].size();++i){
int v=G[u][i];
if (v!=father&&!vis[v]){
InitDP(v,u);
dp[u]+=dp[v];
max_dp[u]=max(max_dp[u],dp[v]);
}
}
max_dp[u]=max(max_dp[u],tot-dp[u]);
if (max_dp[root]>max_dp[u]) root=u;
}
int n;
inline int GetRoot(int u,int s){
tot=s,root=0;
InitDP(u,0);
return root;
}
inline void InitDep(int u,int father,int dep){
sz=max(sz,dep);
A[dep].x++;
for (register int i=0;i<(int)G[u].size();++i){
int v=G[u][i];
if (v!=father&&!vis[v]){
InitDep(v,u,dep+1);
}
}
}
inline void Calc(int u,int f){
sz=0;
InitDep(u,0,f==-1?1:0);
Mul(f);
}
inline void dfs(int u){
vis[u]=true;
Calc(u,1);
for (register int i=0;i<(int)G[u].size();++i){
int v=G[u][i];
if (!vis[v]){
Calc(v,-1);
dfs(GetRoot(v,dp[v]));
}
}
}
int main(){
n=read();
max_dp[0]=n;
for (register int i=1;i<n;++i){
int u=read()+1,v=read()+1;
AddEdge(u,v);
AddEdge(v,u);
}
dfs(GetRoot(1,n));
double ret=0;
for (register int i=0;i<n;++i){
ret+=(double)ans[i]/(i+1);
}
printf("%.4lf\n",ret);
}

评论