您的位置:首页 > 其它

CodeforcesRound#253(Div2) D Andrey and Problem

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

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

因为sum(a)一定等于1,所以对于n>=1,a
<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>=1,从中取任意个,获得1的概率一定小于50%。

证明2:对于a
中的元素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);
}


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Codeforces acm
相关文章推荐