zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    RabbitMQ死信队列另类用法之复合死信
    Asp.NetCore轻松学-使用Docker进行容器化托管
    Asp.NetCore轻松学-使用Supervisor进行托管部署
    Asp.NetCore轻松学-部署到 Linux 进行托管
    Asp.NetCore轻松学-部署到 IIS 进行托管
    一个提问引发的职业规划热议-拨开迷雾,走向光明
    Asp.Net Core 轻松学-使用MariaDB/MySql/PostgreSQL和支持多个上下文对象
    Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章
    Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库
    Asp.Net Core 轻松学-多线程之Task(补充)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10382603.html
Copyright © 2011-2022 走看看