CF1267G 题解
Yizhixiaoyun · · 题解
想了想还是写吧,毕竟是一道比较神的期望
首先是一个简单的贪心思路:能抽卡的先抽卡,然后再去买。
原因显然,如果先买了卡,那么接下来抽卡就很有可能会抽到重复的卡,因此先抽卡再买卡。
如果我们已经有了
除了最后一次之外,其他的次数都可以让我们获得
接着寻找抽卡与买的分界线。考虑把所有直接购买的花费均摊到每次之中。令已有的卡价值为
接着假设
其中组合数可以预处理,
愉快结束。
#include<bits/stdc++.h>
using namespace std;
const int maxn=102;
const int maxm=10002;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int n,x;
double sum,ans;
int a[maxn];
double C[maxn][maxn],dp[maxn][maxm];
inline void init(){
n=read();x=read();
for(register int i=1;i<=n;++i) a[i]=read();
C[0][0]=1;dp[0][0]=1;
for(register int i=1;i<=n;++i){
C[i][0]=1;
for(register int j=1;j<=i;++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
}
for(register int i=1;i<=n;++i){
for(register int j=i-1;j>=0;--j){
for(register int k=sum;k>=0;--k) dp[j+1][k+a[i]]+=dp[j][k];
}
sum+=a[i];
}
}
int main(){
init();
for(register int i=0;i<=n-1;++i){
for(register int j=0;j<=sum;++j) ans+=min((sum-j)/(n-i),x*(1.0*n/(n-i)+1)/2)*dp[i][j]/C[n][i];
}
printf("%.8lf",ans);
}