解析
有些遗憾的一个题。
几乎已经做出来了,但最后把买的代价看成平均数确实没有想到。
还有那个背包我觉得直接做会炸精度,就开始各种玩泥巴。
悲。
比较显然的结论是最优解必然是先抽抽抽然后再买买买。
剩 i 个宝物的时候抽出一个新宝物的期望代价比较好求,是 (ni+1)x2(\frac n i+1)\frac x 2(in+1)2x。
那么现在就是这么一个问题:我有一些宝物,可以直接买,也可以花一定代价抽一个。
那我抽还是买?显然是要看剩下宝物的价格的平均数了。
再看看 ∑c<=10000\sum c<=10000∑c<=10000 的数据范围,不难想到做一个简单的dp fi,jf_{i,j}fi,j 表示 iii 个宝物价格和是 jjj 的概率。
直接做的话应该是统计方案数再除个组合数就行,但浮点运算组合数就是在搞笑了。
解决方法就是把组合数揉到dp转移的里面,其实也挺直观的。
然后还有一个问题就是怎么统计直接买的贡献。直观考虑的话,直接加上其价格之和就行,但是由于其子集也会被考虑到,所以正确的打开方式应该是统计价格的平均数。也就是说:把直接买的过程看成支付 nnn 次平均数的过程,这对最终答案显然是没有影响的。
//luogu
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=5050;
const int mod=998244353;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;
double f[105][10050],x;
int c[105];signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifint S=0;n=read();x=read();for(int i=1;i<=n;i++) c[i]=read(),S+=c[i];f[0][0]=1;for(int i=1;i<=n;i++){for(int k=n;k>=1;k--){for(int j=c[i];j<=S;j++) f[k][j]+=f[k-1][j-c[i]]/(1.0*(n-k+1)/k);}}double ans(0);for(int i=1;i<=n;i++){for(int j=0;j<=S;j++){ ans+=f[i][j]*min(1.0*j/i,x/2*(1.0*n/i+1));//if(f[i][j]>1e-9)// printf("i=%d j=%d f=%.6lf ans=%.6lf\n",i,j,f[i][j],ans);}}printf("%.10lf\n",ans);return 0;
}