和上次的上海邀请赛的那个dp优化技巧类似。都是考虑double精度,来减少枚举次数。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100005;
const int maxm = 200005;
struct Edge
{
int v;
Edge *next;
}*H[maxn], E[maxm], *edges;
double a[maxn];
double res[maxn];
double res2[maxn];
int n;
void init()
{
edges = E;
for(int i = 0; i <= n; i++) H[i] = 0;
}
void addedges(int u, int v)
{
edges->v = v;
edges->next = H[u];
H[u] = edges++;
}
void dfs(int u, int fa, int dep)
{
a[u] = dep;
for(Edge *e = H[u]; e; e = e->next) if(e->v != fa) dfs(e->v, u, dep + 1);
}
void work()
{
for(int i = 2; i <= n; i++) {
int fa;
scanf("%d", &fa);
addedges(i, fa);
addedges(fa, i);
}
dfs(1, 1, 0);
sort(a+1, a+n+1);
double ans = 0;
if(n <= 40) {
for(int i = 1; i <= n; i++)
for(int j = 1; j < i; j++) {
double t = (a[i] + 1) * (a[j] + 1) / (a[i] + a[j] + 2);
ans += t * res2[j-1] / (res2[n] - 1 - n);
}
}
else {
for(int i = 1; i <= n; i++)
for(int j = max(1, i - 40); j < i; j++) {
double t = (a[i] + 1) * (a[j] + 1) / (a[i] + a[j] + 2);
ans += t * res[n-j+1];
}
}
printf("%.6f\n", ans);
}
int main()
{
res[0] = res2[0] = 1;
for(int i = 1; i <= 70; i++) res[i] = res[i-1] / 2, res2[i] = res2[i-1] * 2;
while(scanf("%d", &n) != EOF) {
init();
work();
}
return 0;
}