1 条题解
-
0
自动搬运
来自洛谷,原作者为

_rqy
**搬运于
2025-08-24 21:47:55,当前版本为作者最后更新于2017-12-23 10:31:35,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
嗯...既然这题没有题解那我就来写一个吧!
显然,题目等价于同时修建这条道路时,首次连通的时间期望值。
我们令为首次连通的时间(设它为随机变量)的概率分布函数,也就是,其中,那么根据期望的定义有
$$\begin{aligned}E(X)&=\int_0^1p(x)x\mathrm{d}x\\&=\int_0^1p(x)\int_0^x\mathrm{d}t\,\mathrm{d}x\\&=\int_0^1\int_t^1p(x)\mathrm{d}x\,\mathrm{d}t\\&=\int_0^1P(t)\mathrm{d}t\end{aligned} $$所以我们只需计算即可。
考虑如果,也就是说图在时刻不连通,那么我们可以枚举结点在时刻的连通块里有哪些点。如果有这些点,那么首先要连通(概率我们定义为),其次,里的点和其它点之间的边的都大于(概率为,其中为的补集,表示点集之间的边数);由于这两个事件是独立的,所以总的概率是。也可以类似计算,递推式为:
$$P_S(t)=\sum_{1\in S_0 \subsetneq S}(1-t)^{T(S_0, S - S_0)}\left[1-P_{S_0}(t)\right]\qquad(1\in S) $$边界条件是,因为单一的点永远是连通的。
那么有
$$\begin{aligned}\int_0^1P_S(t)\mathrm{d}t&=\sum_{1\in S_0 \subsetneq S}\int_0^1(1-t)^{T(S_0, S - S_0)}\left[1-P_{S_0}(t)\right]\mathrm{d}t\\&=\sum_{1\in S_0 \subsetneq S}\left[\int_0^1(1-t)^{T(S_0, S - S_0)}-(1-t)^{T(S_0, S - S_0)}P_{S_0}(t)\mathrm{d}t\right]\\&=\sum_{1\in S_0 \subsetneq S}\left[\frac{1}{1+T(S_0, S - S_0)}-\int_0^1(1-t)^{T(S_0, S - S_0)}P_{S_0}(t)\mathrm{d}t\right]\end{aligned} $$同理,
$$\int_0^1(1-t)^kP_S(t)\mathrm{d}t=\sum_{1\in S_0 \subsetneq S}\left[\frac{1}{1+k+T(S_0, S - S_0)}-\int_0^1(1-t)^{k+T(S_0, S - S_0)}P_{S_0}(t)\mathrm{d}x\right] $$边界条件:$\int_0^1P_{\{1\}}(t)(1-t)^k{\rm d}t=\int_0^10{\rm d}t=0$
而我们要求的就是
$$EX = \int_0^1P(t){\rm d}t =\int_0^1(1-t)^0P_{\{1,2,\dots,n\}}(t){\rm d}t $$于是关于递推即可。按从小到大计算,每次枚举子集之后利用位运算求出,总时间复杂度。
PS:搞了一晚上终于抢下rk1了。
#include <algorithm> #include <cstdio> #include <cstring> const int N = 10; const int M = 45 + 1; bool vis[1 << N][M]; int siz[1 << N], link[N]; double f[1 << N][M]; int main() { int n, m; scanf("%d%d", &n, &m); int lim = 1 << n; for (int i = 0, x, y; i < m; ++i) { scanf("%d%d", &x, &y); --x; --y; link[x] |= (1 << y); link[y] |= (1 << x); } for (int S = 1; S < lim; ++S) siz[S] = siz[S & (S - 1)] + 1; for (int S1 = 3; S1 < lim; ++S1) if (S1 & 1) { for (int S2 = (S1 - 1) & S1; S2 != 0; S2 = (S2 - 1) & S1) if (S2 & 1) { int T = 0; for (int i = 0; i < n; ++i) if ((S1 >> i) & (~S2 >> i) & 1) T += siz[link[i] & S2]; for (int i = 0; i + T <= m; ++i) f[S1][i] += 1.0 / (i + T + 1) - f[S2][i + T]; } } printf("%.6lf\n", f[lim - 1][0]); return 0; }
- 1
信息
- ID
- 2416
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者