题面
Sol
方法一
直接状压就好了
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
int n;
double p[21], f[1 << 20];
int main(RG int argc, RG char *argv[]){
while(scanf("%d", &n) != EOF){
for(RG int i = 1; i <= n; ++i) scanf("%lf", &p[i]);
RG int S = 1 << n; Fill(f, 0);
for(RG int i = S - 2; ~i; --i){
RG double s = 1.0;
for(RG int j = 1; j <= n; ++j) if(~i & (1 << (j - 1))) s -= p[j];
s = 1.0 - s, f[i] = 1.0 / s;
for(RG int j = 1; j <= n; ++j)
if(~i & (1 << (j - 1))) f[i] += p[j] * f[i | (1 << (j - 1))] / s;
}
printf("%.6lf\n", f[0]);
}
return 0;
}
方法二
方法一实在太水了,显然不是重点
下面介绍一种容斥方法
min-max容斥
E[max(S)]=∑(−1)k+1E[min(S′)]
E
[
m
a
x
(
S
)
]
=
∑
(
−
1
)
k
+
1
E
[
m
i
n
(
S
′
)
]
其中集合
S′⊆S
S
′
⊆
S
,
k=|S′|
k
=
|
S
′
|
max(S)
m
a
x
(
S
)
指的是这个集合内最后出现的元素
min(S)
m
i
n
(
S
)
指的是这个集合内最先出现的元素
E
E
表示期望第几步出现
具体到这个题
就是要求全集
)]
)
]
E[min(S′)]
E
[
m
i
n
(
S
′
)
]
就是指
S′
S
′
任意出现一个的期望步数
举例:
每步出现
xi
x
i
的概率
pi
p
i
min{x1,x2,x3}
m
i
n
{
x
1
,
x
2
,
x
3
}
的概率就是
p1+p2+p3
p
1
+
p
2
+
p
3
期望步数就是
1p1+p2+p3
1
p
1
+
p
2
+
p
3
然后就容斥一下这个题
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
int n;
double p[21], ans;
IL void Dfs(RG int x, RG double E, RG int op){
if(x > n){
if(E > 1e-7) ans += 1.0 * op / E;
return;
}
Dfs(x + 1, E, op);
Dfs(x + 1, E + p[x], -op);
}
int main(RG int argc, RG char *argv[]){
while(scanf("%d", &n) != EOF){
for(RG int i = 1; i <= n; ++i) scanf("%lf", &p[i]);
ans = 0, Dfs(1, 0, -1);
printf("%.6lf\n", ans);
}
return 0;
}