太神了这题,膜拜出题人 orz。

思考一

首先是大家都提到的一点,先抽卡再买。这里来做个数学分析。

假设我们还剩 \(k\) 种没有买,其实我们是有式子来算出它的花费期望的。WIKI 上提到,假设一个事件的概率为 \(p\),则遇到它的期望为 \(\frac{1}{p}\),因此,对于这个题,抽到一个新物品的概率显然为 \(\frac{k}{n}\),那么期望次数就为 \(\frac{n}{k}\),这里面除了最后一次之外,其余的次数的花费都为 \(x-\frac{x}{2}=\frac{x}{2}\),而最后一次的花费恰好为 \(x\),因此可以得出有 \(k\) 种没买的情况下,抽到新物品的期望花费公式:

\[E(k)=\frac{x}{2}\times (\frac{n}{k}-1)+x
\]

可以看出这个式子是关于 \(k\) 单调递增的,也就是说,越晚抽卡,花费的代价越大,因此才有了上述的结论:先抽卡再买。

思考二

既然我们能直接算出期望了,那我们直接比较一下抽卡和买哪个更赚不就行了吗。现在抽卡的期望我们有了,还需要一个买东西的期望。其实,因为每个东西的价值都是固定的,所以这个期望实际上就是平均数,那么我们算出这个平均数,每次都和当前的抽卡期望比较,选个最小的执行不就行了,搞定!紫题也不过如此。

但是不对,有点小问题。因为每个物品的价值都是不一样的,我们抽到不同的物品,最后计算出来的平均数也不一样。难道要枚举一遍全部的可能情况,再算一个平均数的平均数?又或者还要分情况讨论?那不就变成搜了吗,晕。

思考三

不对,除了搜还能写 DP,但是就是不知道状态怎么设计。

想想看,我们现在需要的东西有什么。需要计算抽卡期望,那么我们需要的东西就是当前剩余的物品个数,还有一个是平均数,那我们直接用剩余价值除以剩余个数不就行了吗!开一个两个维度的 DP:剩余个数,剩余价值。发现它变成了一个背包 DP

现在来想状态转移。其实到这一步就和常规背包 DP 差不多了。定义初始状态 \(f_{n,sum}=sum\),即不抽卡的期望花费为总价值,然后从剩余容量由大到小开始枚举所有物品,然后尝试转移就行了。

思考四

本来以为都快过了,但是写一半卡住了。

具体是卡在状态转移的时候,突然发现这个转移根本就没法实现。因为我们每次转移可能的来源有两个:一个是购买,一个是抽卡。买还好说,但是抽卡不行,因为不是整数,而我们没办法访问一个小数下标。

那么怎么办呢,感觉又到了瓶颈了。

首先这个思路是绝对正确的,我们整理一下现在都有什么了。我们可以求出在某个状态下的最优代价,那么,假如我们再维护一个出现概率的话,就能根据期望的定义,直接用概率乘代价去算了。那么我们不妨把我们设计的 DP 数组改一下,不维护期望了,改成维护当前状态的概率,再求一下抽卡期望和平均值的最小值,二者一乘就是答案。又因为这个题的总方案数是一定的(可以用组合数求),那么我们不妨再转换一下思路,改成求当前状态的总方案数,和总方案数一比就是答案。

思考五

我们在思路整理的时候忽略了一些小细节,比如,如果当前的最优策略是抽卡,则若没抽中,下次的最优策略还是抽卡,直到抽到一个新的。简单证明一下,假如你抽卡没抽中,那么除了钱少了点,此外什么都没变,因此 \(E(k)\) 和平均数完全不会有任何变化。知道了这点,我们才能用 \(E(k)\) 这样一条路走到黑的模型来计算答案。

还有一点,打完提交的时候莫名其妙 RE 了,后来发现是阶乘乘炸了(\(100!\) 确实还挺大的),然后把阶乘函数改成 Double 就过了,会丢精度,但是不影响答案。

代码

#include<bits/stdc++.h>
using namespace std;
#define div *1.0/
int n,x;
int c[101];
double f[101][10001];
long double fac[101];
inline void prework(){
fac[0]=1;
for(int i=1;i<=100;++i){
fac[i]=fac[i-1]*i;
}
}
inline double E(int k){
return (n div k -1)*(x div 2)+x;
}
inline double C(int x,int y){
return fac[x] div (fac[y]*fac[x-y]);
}
int main(){
int sum=0;
cin>>n>>x;
prework();
for(int i=1;i<=n;++i){
cin>>c[i];
sum+=c[i];
}
f[n][sum]=1;
for(int i=1;i<=n;++i){
for(int j=0;j<=n-1;++j){
for(int k=0;k<=sum-c[i];++k){
f[j][k]+=f[j+1][k+c[i]];
}
}
}
long double ans=0;
for(int i=1;i<=n;++i){
for(int j=0;j<=sum;++j){
ans+=(f[i][j] div C(n,n-i)) * min(j div i,E(i));
}
}
printf("%.20Lf",ans);
}

[Tkey] CodeForces 1267G Game Relics的更多相关文章

  1. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  2. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  3. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

  4. 【Codeforces 738A】Interview with Oleg

    http://codeforces.com/contest/738/problem/A Polycarp has interviewed Oleg and has written the interv ...

  5. CodeForces - 662A Gambling Nim

    http://codeforces.com/problemset/problem/662/A 题目大意: 给定n(n <= 500000)张卡片,每张卡片的两个面都写有数字,每个面都有0.5的概 ...

  6. CodeForces - 274B Zero Tree

    http://codeforces.com/problemset/problem/274/B 题目大意: 给定你一颗树,每个点上有权值. 现在你每次取出这颗树的一颗子树(即点集和边集均是原图的子集的连 ...

  7. CodeForces - 261B Maxim and Restaurant

    http://codeforces.com/problemset/problem/261/B 题目大意:给定n个数a1-an(n<=50,ai<=50),随机打乱后,记Si=a1+a2+a ...

  8. CodeForces - 696B Puzzles

    http://codeforces.com/problemset/problem/696/B 题目大意: 这是一颗有n个点的树,你从根开始游走,每当你第一次到达一个点时,把这个点的权记为(你已经到过不 ...

  9. CodeForces - 148D Bag of mice

    http://codeforces.com/problemset/problem/148/D 题目大意: 原来袋子里有w只白鼠和b只黑鼠 龙和王妃轮流从袋子里抓老鼠.谁先抓到白色老鼠谁就赢. 王妃每次 ...

  10. CodeForces - 453A Little Pony and Expected Maximum

    http://codeforces.com/problemset/problem/453/A 题目大意: 给定一个m面的筛子,求掷n次后,得到的最大的点数的期望 题解 设f[i]表示掷出 <= ...

随机推荐

  1. 关于MultipartFile

    首先,他来自spring框架,用于处理文件上传的问题 一般来讲,这个接口主要是实现以表单形式上传文件的功能 常用方法: getOriginalFileName:获取文件名+拓展名 getContent ...

  2. 全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

    全网最适合入门的面向对象编程教程:27 类和对象的 Python 实现-Python 中异常层级与自定义异常类的实现 摘要: 本文主要介绍了在使用 Python 进行面向对象编程时,异常的层级和如何使 ...

  3. jmeter forEach循环获取response参数值进行接口请求

    jmeter forEach循环获取response参数值进行接口请求 注意: 一,ForEach控制器 输入变量前缀:输入正则表达式变量的引用名称即可 Start index for loop(ex ...

  4. Vue Hook 封装通用型表格

    一.创建通用型表格的需求 实现一个通用型表格组件,具备以下功能: 动态列配置. 分页功能. 排序功能. 可扩展的行操作功能. 二.设计通用型表格组件 首先,需要设计一个基础的表格组件,它接受列配置.数 ...

  5. 什么是web3 为什么web3很重要

    中心化网络已经帮助数十亿人融入了互联网,并在其上创建了稳定.可靠的基础设施. 与此同时,少数中心化巨头几乎垄断了互联网,甚至可以为所欲为. Web3 是摆脱这一困境的方案. 不同于科技巨头垄断的传统互 ...

  6. 【RabbitMQ】06 Spring整合RabbitMQ

    首先生产者和消费者需要的Maven依赖是一样的 <?xml version="1.0" encoding="UTF-8"?> <project ...

  7. python画图报错:OSError: 'seaborn-whitegrid' is not a valid package style

    解决方法: https://stackoverflow.com/questions/78019854/matplotlib-seaborn-whitegrid-is-not-a-valid-packa ...

  8. 使用浪潮AI计算平台之分布式计算(Tensorflow框架下 PS/Worker模式下的异步计算)

    虽然Tensorflow一直都是支持分布式计算的,但是由于只有一台电脑,一个GPU,所以别说分布式的tensorflow的使用了,就是单机多卡都是没有使用过的,由于后来可以有机会使用这个浪潮的AI计算 ...

  9. 【转载】 IEEE Signal Processing Letters(SPL)投稿经验分享

    版权声明:本文为CSDN博主「yellow7-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/weixin_4 ...

  10. 凸优化: 回溯线搜索(Backtracking line search)

    声明: 本文大量摘录 https://www.cnblogs.com/kemaswill/p/3416231.html 内容. ==================================== ...