题意
有 n 个 事 件 , 每 个 事 件 发 生 的 概 率 为 p i . 要 求 取 其 中 一 些 事 件 构 成 的 子 集 , 使 得 选 出 来 的 事 件 中 只 发 生 一 件 的 概 率 最 大 . 求 最 大 的 概 率 . 有n个事件,每个事件发生的概率为p_i.\newline 要求取其中一些事件构成的子集,使得选出来的事件中只发生一件的概率最大.\newline 求最大的概率. 有n个事件,每个事件发生的概率为pi.要求取其中一些事件构成的子集,使得选出来的事件中只发生一件的概率最大.求最大的概率.
题解
真的是非常大胆,数据范围
100
100
100的题目标算复杂度
n
l
o
g
n
nlogn
nlogn,佩服一下出题人.
我觉得这题能够大胆贪心的大佬也是胸有成竹,心里非常沉稳.
标算算法把
p
p
p从大到小排序,选择前缀的事件只发生一件的最大概率即可.
为什么可以这么做?
我们需要最大化
∏
(
1
−
p
i
)
⋅
∑
p
i
1
−
p
i
\prod(1-p_i)\cdot\sum\frac{p_i}{1-p_i}
∏(1−pi)⋅∑1−pipi
令
P
=
∏
(
1
−
p
i
)
,
S
=
∑
p
i
1
−
p
i
P=\prod(1-p_i),S=\sum\frac{p_i}{1-p_i}
P=∏(1−pi),S=∑1−pipi.
我们假设已经有一个集合,当我们再在这个集合中加入一个发生概率
p
i
p_i
pi的事件的时候,该集合中事件仅发生一件的概率会增加
Δ
=
−
P
⋅
S
+
P
(
1
−
p
i
)
⋅
(
S
+
p
i
1
−
p
i
)
=
P
⋅
p
i
(
1
−
S
)
\Delta=-P\cdot S+P(1-p_i)\cdot(S+\frac{p_i}{1-p_i})=P\cdot p_i(1-S)
Δ=−P⋅S+P(1−pi)⋅(S+1−pipi)=P⋅pi(1−S)
这样的话我们发现当我们加入一个事件的时候,仅有
S
<
1
S<1
S<1会导致仅发生一件事的概率增加.
假设我们加入两件发生概率分别为
p
i
p_i
pi和
p
j
p_j
pj的事件.则发生概率变化值之差为
Δ
i
−
Δ
j
=
P
⋅
p
i
⋅
(
1
−
S
)
−
P
⋅
p
j
⋅
(
1
−
S
)
=
P
⋅
(
1
−
S
)
⋅
(
p
i
−
p
j
)
>
0
\Delta_i-\Delta_j=P\cdot p_i\cdot(1-S)-P\cdot p_j\cdot(1-S)=P\cdot(1-S)\cdot(p_i-p_j)>0
Δi−Δj=P⋅pi⋅(1−S)−P⋅pj⋅(1−S)=P⋅(1−S)⋅(pi−pj)>0.
当
S
<
1
S<1
S<1时我们可以得知
p
i
>
p
j
p_i>p_j
pi>pj.
证毕.
最后你需要求前缀概率.
令
p
0
[
i
]
p0[i]
p0[i]表示前
i
i
i件事都不发生的概率,
p
1
[
i
]
p1[i]
p1[i]表示前
i
i
i件事发生一件的概率.
p0[i]=p0[i-1]*(1-p[i]); // 前i-1件事都不发生的概率乘上这件事也不发生的概率.
p1[i]=p0[i-1]*p[i]+p1[i-1]*(1-p[i]); // 前i-1件事都不发生的概率乘这件事发生的概率加上前i-1件事发生一件的概率乘这件事不发生的概率.
好了.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int aoi=1018;
typedef double db;
db p[aoi],p0[aoi]={1.0},p1[aoi];
int main() {
int n=read(),i;
for (i=1;i<=n;++i) scanf("%lf",&p[i]);
sort(p+1,p+n+1,greater<db>());
for (i=1;i<=n;++i)
p0[i]=p0[i-1]*(1-p[i]),
p1[i]=p0[i-1]*p[i]+p1[i-1]*(1-p[i]);
printf("%.9lf\n",*max_element(p1+1,p1+n+1));
}
谢谢大家.