• CF1267GGame Relics【数学期望,dp】


    正题

    题目链接:https://www.luogu.com.cn/problem/CF1267G


    题目大意

    给出\(n\)个物品,你可以进行如下操作

    • 花费\(x\)获得随机一个物品。
    • 花费\(c_i\)获得第\(i\)个物品。

    \(1\leq n\leq 100,1\leq x\leq 10000,\sum a_i\leq 10^4\)


    解题思路

    一个显然的策略是我们先roll完再买,所以我们可以分开考虑两部分先。

    首先假设我们roll到了\(x\)个物品,显然所有大小为\(x\)的物品集合都是等概率出现的。而至于roll出\(x\)个物品的期望花费我们也很好算。

    但是我们显然很难从一种情况下的下一步方案考虑,因为能到达每个方案的期望都是不同的,而我们不可能记录所有方案。

    但是有一个很巧妙的方法,我们花钱也可以视为随意\(roll\)物品,假设目前没有获得的物品费用和为\(s\),个数为\(k\),那么我们就可以视为花费\(\frac{s}{k}\)的期望随机\(roll\)出一个物品。

    此时两种方案造成的结果都是多一个随机未获得物品,但是花费不同,我们直接取\(min\)即可。

    那么现在的做法已经很显然了,设\(f_{i,j}\)表示\(i\)个物品的集合中花费和为\(j\)的概率,然后考虑两种方案的哪个更优就好了。

    时间复杂度:\(O(n\sum a_i)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,sum;
    double ans,x,f[110][110000];
    int main()
    {
    	scanf("%d%lf",&n,&x);x/=2.0;
    	f[0][0]=1;
    	for(int i=1,a;i<=n;i++){
    		scanf("%d",&a);sum+=a;
    		for(int j=i;j>=1;j--)
    			for(int k=sum;k>=a;k--)
    				f[j][k]+=f[j-1][k-a]*j/double(n-j+1);
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=0;j<=sum;j++)
    			if(f[i][j]!=0.0)
    				ans=(ans+f[i][j]*min(((double)n/i+1.0)*x,(double)j/i));
    	printf("%.12lf\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    ibatis报错
    struts配置时遇到的几个问题
    快乐工作,快乐生活
    浅谈协方差矩阵理解篇
    类成员变量初始化
    类对象所占内存空间总结
    const 成员函数
    Qt对话框QDialog
    const引用返回值
    Qt 对象间的父子关系
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15841139.html
Copyright © 2020-2023  润新知