CodeforcesRound#253(Div2) D Andrey and Problem

来源:互联网 发布:单片机编程题 编辑:程序博客网 时间:2024/04/30 13:21

首先将数组a从大到小排序,因为直觉上我们容易yy出a[i]越大越容易得到1,事实上也确实是对的,具体证明如下

证明1:对于a[n],n>=1,从中取任意两个,获得1的概率一定小于50%。

因为sum(a)一定等于1,所以对于n>=1,a[n]<0.5。

然后不妨设为m、n,且m>=n。

那么获得1的概率为(1-m)*n+(1-n)*m=n+m-2mn<=2m-2m^2=2(1-m)m=2*(1/2-(m-1/2))*(1/2+m-1/2)=2*(1/4-(m-1/2)^2)<0.5

这样我们可以进一步得出,对于a[n],n>=1,从中取任意个,获得1的概率一定小于50%。

证明2:对于a[n]中的元素a,b,c,且a>b>c,选择两个时,一定有a优于c。

选择a时,(1-a)b+a(1-b)

选择c时,(1-c)b+c(1-b)

作差得到(a-c)*(1-2b) ,b一定小于0.5,a一定大于c,所以一定有a优于c。

b可以替换为不包含a[0]的任意组合下获得1的概率。可以发现证明2仍然成立。

接下来的证明就比较简单了,对于选择N个数使得最容易得到1,我们可以始终把概率最小的一项替换为概率大的。最终就能够得到选择前N个概率得到1的可能性就是选择N个概率中得到1的可能性中最大的。

有了这个结论然后只要暴力就好了,或者dp也可以,用二维数组,dp[i][j]表示选择i个概率时得到j的可能性,这题j只要0或1。

有状态转移方程如下

f[i][0]=f[i-1][0]*(1-a[i])    

f[i][1]=f[i-1][0]*a[i]+f[i-1][1]*(1-a[i])

最后是一段ac的代码

#include<cstdio>#include<algorithm>using namespace std;bool cmp(double a, double b){return a>b;}int main(){int n;double a[105], sum, MAX;scanf("%d", &n);for (int i = 0; i<n; i++)scanf("%lf", &a[i]);sort(a, a + n, cmp);MAX = 0;for (int i = 1; i <= n; i++){sum = 0;for (int j = 0; j<i; j++){double temp = a[j];for (int k = 0; k<i; k++){if (j != k)temp*= 1 - a[k];}sum += temp;}MAX = max(sum, MAX);}printf("%.12lf\n", MAX);}



                                             
0 0
原创粉丝点击