Codeforces 442B Andrey and Problem 大胆猜想,小心求证

大胆猜想,小心求证

题意

有 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} (1pi)1pipi
P = ∏ ( 1 − p i ) , S = ∑ p i 1 − p i P=\prod(1-p_i),S=\sum\frac{p_i}{1-p_i} P=(1pi),S=1pipi.
我们假设已经有一个集合,当我们再在这个集合中加入一个发生概率 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) Δ=PS+P(1pi)(S+1pipi)=Ppi(1S)
这样的话我们发现当我们加入一个事件的时候,仅有 S &lt; 1 S&lt;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 ) &gt; 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)&gt;0 ΔiΔj=Ppi(1S)Ppj(1S)=P(1S)(pipj)>0.
S &lt; 1 S&lt;1 S<1时我们可以得知 p i &gt; p j p_i&gt;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));
}

谢谢大家.

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/83588874
今日推荐