样例输入:
2 0.1
1 1
样例输出:
0.6
题意:有n个装有白球或者黑球的盒子,每个盒子中为白球或者黑球的概率都是1/2,只有打开盒子后才能知道盒子中是白球还是黑球,打开第i个盒子需要代价wi。我们可以花费C代价来询问现在未打开的盒子里面还有多少黑球,问我们确定所有盒子中装入的球的颜色的最小成本的数学期望是多少?
分析:先来看一下这个询问有什么用,因为我们要知道所有盒子里面分别装的球的颜色,那么如果我们不知道盒子里面一共有多少黑球和白球的话那我们只能把所有盒子都打开才能确定每个盒子中分别装着什么颜色的球,这样对应着一种代价,当然如果我们知道盒子里面黑球的个数为x,我们现在开了一些盒子,已经发现了x个黑球,那么我们就没必要再继续开剩余的盒子了,这也就是我们询问的意义。由于每个盒子装有黑球或者白球的可能性是相同的,所以我们开盒子优先开所需代价小的盒子,也就是说我们首先需要对盒子按照代价从小到大进行排序,然后依次开盒子直到把一种颜色的球全部开出来为止。
先来分析不用全部把盒子打开的最小代价期望:
由于黑球和白球的个数是未知的,在有n个球的前提下,一共有2^n种情况,假设我们开到第m个盒子时恰好把某种颜色的球全部开出来了,那么这种情况对应着xxx……xx1000……0或者xxx……xx0111……1,因为当我们开到第m个盒子恰好开出了某种颜色全部的球,那么说明第m个盒子一定就是开的该颜色的盒子,而之后所有的盒子里面都是装有另一种颜色的球,由于前m-1个盒子种装有的球是随机的,所以总的情况数就是2^(m-1)*2=2^m,对应的概率就是2^m/2^n=2^(m-n),这种情况下所需花费的代价就是C+,所以总的花费期望就是
还有一种情况就是把所有盒子都打开时对应着最小期望,这种请况比较容易计算,直接把打开所有盒子的代价相加即可得到,最后只需要在这两种情况中取一个最小值即可。
不要忘记对打开盒子的代价进行从小到大排序
下面是代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e5+10;
double w[N];
double sum[N];
int main()
{
int n;
double c;
cin>>n>>c;
for(int i=1;i<=n;i++)
scanf("%lf",&w[i]);
sort(w+1,w+n+1);//将代价从小到大排序
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+w[i];
double ans=c;
double t=0.5;
for(int i=n-1;i>=1;i--)
ans+=t*sum[i],t/=2;
if(ans>sum[n]) ans=sum[n];
printf("%.10lf",ans);
return 0;
}