intmain(){ while (scanf("%d", &n) == 1) { for (int i = 0; i < n; i++) { scanf("%lf", a + i); } double ans = 0.0; for (int s = 1; s < (1 << n); s++) { int c = 0; double sum = 0; for (int i = 0; i < n; i++) { if (s >> i & 1) { c++; sum += a[i]; } } if (c % 2) ans += 1.0 / sum; else ans -= 1.0 / sum; } printf("%.4lf\n", ans); } return0; }
「HAOI2015」按位或
初始有一个数 $0$,每秒有 $p_i$ 的概率或上整数 $i(0 \le i \le 2^n-1)$,求期望多少秒后数变成 $2^n−1$。
逐位考虑,即某一个位置被被覆盖的期望时间最大值,套用 min-max 容斥。
我们就是要求 $\min(S)={1 \over \sum_{T\cap S \neq \varnothing} p_T}$,考虑分母的补集 $1-\sum_{T \subseteq \overline {S} } p_T$,使用 SOS DP 容易计算。
intmain(){ scanf("%d", &n); int ss = 1 << n, ok = 0; for (int i = 0; i < ss; i++) { scanf("%lf", a + i); if (a[i] > eps) { ok |= i; } } if (ok != ss - 1) returnputs("INF"), 0; for (int i = 0; i < n; i++) { for (int s = 0; s < ss; s++) { if (s >> i & 1) a[s] += a[s ^ (1 << i)]; } } double ans = 0; for (int s = 0; s < ss; s++) { double p = 1.0 - a[ss - 1 - s]; if (p > eps) p = 1.0 / p; else p = 0; if (__builtin_popcount(s) % 2) ans += p; else ans -= p; } printf("%.6lf\n", ans); return0; }