解析
有些遗憾的一个题。
几乎已经做出来了,但最后把买的代价看成平均数确实没有想到。
还有那个背包我觉得直接做会炸精度,就开始各种玩泥巴。
悲。
比较显然的结论是最优解必然是先抽抽抽然后再买买买。
剩 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_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int 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;
}
本文解析了一种关于资源分配的问题,如何在有限预算下,通过抽宝物和购买来最大化期望收益。涉及动态规划求解概率分布和期望值,以及如何巧妙地处理组合数问题。关键在于计算剩余宝物的平均价值并应用到决策过程中。
866

被折叠的 条评论
为什么被折叠?



