http://codeforces.com/problemset/problem/261/B
题目大意:给定n个数a1…an(n<=50,ai<=50),随机打乱后,记Si=a1+a2+a3…+ai,问满足Si<=p的i的最大值的期望.(p<=50)
(大意来自于http://www.cnblogs.com/liu-runda/p/6253569.html)
我们知道,全排列其实等价于我们一个一个地等概率地向一个序列里面插入数值
所以我们可以这么看这道题:
现在有n个数,有n个盒子,等概率地把这些数放入盒子,求Si<=p的max[i]的期望
我们考虑每个盒子对于答案的贡献
如果第一个盒子保存下来了,那么它的贡献就是p(保存下来的概率)
所以我们只需要计算每个盒子保存下来的概率就可以了
我们又发现:如果第i个盒子保存下来了,那么1~(i-1)的盒子一定都保存下来了
不然第i个盒子就不可能保存下来,原文中:
Maxim doesn't let any other guest in the restaurant
even if one of the following guests in the queue would have fit in at the table.
起到了关键作用
所以我们定义f[i][j][k]表示在前i个数中随机的把数放到盒子里
前j个盒子被放满且前j个盒子中的数之和为k的情况出现的概率
那么我们有f[i][j][k] = f[i-1][j][k]*(1 - (j/i)) + f[i-1][j-1][k - a[i]]*(j/i)
则ans = sigma{f[n][i][j]}(1<=i<=n;0<=j<=p)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=*x+ch-'',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = ;
double f[][maxn][maxn];
int a[maxn];
int main(){
int n;read(n);
for(int i=;i<=n;++i) read(a[i]);
int p;read(p);
f[][][] = 1.0;
for(int i=;i<=n;++i){
for(int j=;j<=i;++j){
for(int k=;k<=p;++k){
if(a[i] > k) f[i&][j][k] = f[(i-)&][j][k]*(i-j)/i;
else f[i&][j][k] = f[(i-)&][j][k]*(i-j)/i + f[(i-)&][j-][k-a[i]]*j/i;
}
}
}
double ans = .;
for(int i=;i<=n;++i){
for(int j=;j<=p;++j){
ans += f[n&][i][j];
}
}printf("%.10lf\n",ans);
getchar();getchar();
return ;
}