BZOJ3451:Tyvj1953 Normal

根据期望的线性性,答案就是 \(\sum\) 每个连通块出现次数的期望
而每个连通块次数的期望就是 \(\sum\) 连通块的根与每个点连通次数的期望
也就是对于一条路径 \((i,j)\),设 \(i\) 为根,那么 \(i\) 必须是这条路径第一个被选择的点,概率为 \(\frac{1}{dis(i,j)}\),其中 \(dis(i,j)\) 表示 \((i,j)\) 上的点数
那么只要统计不同的 \(dis(i,j)\) 的个数即可
直接点分治+\(FFT\)

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn(1 << 18);
const int mod(998244353);

inline void Inc(int &x, int y) {
    x = x + y >= mod ? x + y - mod : x + y;
}

inline void Dec(int &x, int y) {
    x = x - y < 0 ? x - y + mod : x - y;
}

inline int Add(int x, int y) {
    return x + y >= mod ? x + y - mod : x + y;
}

inline int Sub(int x, int y) {
    return x - y < 0 ? x - y + mod : x - y;
}

inline int Pow(ll x, int y) {
    register ll ret = 1;
    for (; y; y >>= 1, x = x * x % mod)
        if (y & 1) ret = ret * x % mod;
    return ret;
}

int w[2][maxn], a[maxn], b[maxn], len, l, r[maxn];

inline void Init(int n) {
    int i, x, y;
    for (l = 0, len = 1; len < n; len <<= 1) ++l;
    for (i = 0; i < len; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    x = Pow(3, (mod - 1) / len), y = Pow(x, mod - 2), w[0][0] = w[1][0] = 1;
    for (i = 1; i < len; ++i) w[0][i] = (ll)w[0][i - 1] * x % mod, w[1][i] = (ll)w[1][i - 1] * y % mod;
    for (i = 0; i < len; ++i) a[i] = b[i] = 0;
}

inline void DFT(int *p, int opt) {
    int i, j, k, x, y, t;
    for (i = 0; i < len; ++i) if (i < r[i]) swap(p[i], p[r[i]]);
    for (i = 1; i < len; i <<= 1)
        for (j = 0, t = i << 1; j < len; j += t)
            for (k = 0; k < i; ++k) {
                x = p[j + k], y = (ll)w[opt == -1][len / t * k] * p[j + k + i] % mod;
                p[j + k] = Add(x, y), p[j + k + i] = Sub(x, y);
            }
    if (opt == -1) for (i = 0, t = Pow(len, mod - 2); i < len; ++i) p[i] = (ll)p[i] * t % mod;
}

int n, first[maxn], cnt, cur[maxn], size[maxn], mx[maxn], vis[maxn], rt, sz, deep[maxn], mxd;
long double ans;

struct Edge {
    int to, next;
} edge[maxn << 1];

inline void AddEdge(int u, int v) {
    edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
    edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;
}

void Getroot(int u, int ff) {
    int e, v;
    size[u] = 1, mx[u] = 0;
    for (e = first[u]; ~e; e = edge[e].next)
        if ((v = edge[e].to) != ff && !vis[v]) {
            Getroot(v, u);
            size[u] += size[v];
            mx[u] = max(mx[u], size[v]);
        }
    mx[u] = max(mx[u], sz - size[u]);
    if (mx[u] < mx[rt]) rt = u;
}

void Getdeep(int u, int ff, int d) {
    int e, v;
    ++deep[d], mxd = max(mxd, d);
    for (e = first[u]; ~e; e = edge[e].next)
        if ((v = edge[e].to) != ff && !vis[v]) Getdeep(v, u, d + 1);
}

void Solve(int u) {
    int e, v, i, len1, len2;
    mxd = 0, Getdeep(u, 0, 0), vis[u] = 1;
    Init((mxd << 1) + 1), len1 = mxd << 1;
    for (i = 0; i <= mxd; ++i) a[i] = deep[i], deep[i] = 0;
    DFT(a, 1), len2 = len;
    for (i = 0; i < len2; ++i) a[i] = (ll)a[i] * a[i] % mod;
    DFT(a, -1);
    for (i = 0; i <= len1; ++i) Inc(cur[i + 1], a[i]);
    for (e = first[u]; ~e; e = edge[e].next)
        if (!vis[v = edge[e].to]) {
            mxd = 0, Getdeep(v, u, 1), Init(mxd << 1 | 1), len1 = mxd << 1;
            for (i = 0; i <= mxd; ++i) b[i] = deep[i], deep[i] = 0;
            DFT(b, 1);
            for (i = 0; i < len; ++i) b[i] = (ll)b[i] * b[i] % mod;
            DFT(b, -1);
            for (i = 0; i <= len1; ++i) Dec(cur[i + 1], b[i]);
        }
    for (e = first[u]; ~e; e = edge[e].next)
        if (!vis[v = edge[e].to]) {
            rt = 0, sz = size[v];
            Getroot(v, u), Solve(rt);
        }
}

int main() {
    int i, j, k, u, v;
    memset(first, -1, sizeof(first));
    scanf("%d", &n);
    for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u + 1, v + 1);
    sz = n, mx[0] = n + 1, Getroot(1, 0), Solve(rt);
    for (i = 1; i <= n; ++i) if (cur[i]) ans += 1.0 * cur[i] / (1.0 * i);
    printf("%.4Lf\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjoieryl/p/10382603.html